xnotify.c (10082B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "plerror.h" 7 #include "plgetopt.h" 8 9 #include "prinit.h" 10 #include "prprf.h" 11 #include "prio.h" 12 #include "prcvar.h" 13 #include "prmon.h" 14 #include "prcmon.h" 15 #include "prlock.h" 16 #include "prerror.h" 17 #include "prinit.h" 18 #include "prinrval.h" 19 #include "prthread.h" 20 21 static PRLock* ml = NULL; 22 static PRIntervalTime base; 23 static PRFileDesc* err = NULL; 24 25 typedef struct CMonShared { 26 PRInt32 o1, o2; 27 } CMonShared; 28 29 typedef struct MonShared { 30 PRMonitor *o1, *o2; 31 } MonShared; 32 33 typedef struct LockShared { 34 PRLock *o1, *o2; 35 PRCondVar *cv1, *cv2; 36 } LockShared; 37 38 static void LogNow(const char* msg, PRStatus rv) { 39 PRIntervalTime now = PR_IntervalNow(); 40 PR_Lock(ml); 41 PR_fprintf(err, "%6ld: %s", (now - base), msg); 42 if (PR_FAILURE == rv) { 43 PL_FPrintError(err, " "); 44 } else { 45 PR_fprintf(err, "\n"); 46 } 47 PR_Unlock(ml); 48 } /* LogNow */ 49 50 static void Help(void) { 51 PR_fprintf(err, "Usage: [-[d][l][m][c]] [-h]\n"); 52 PR_fprintf(err, "\t-d debug mode (default: FALSE)\n"); 53 PR_fprintf(err, "\t-l test with locks (default: FALSE)\n"); 54 PR_fprintf(err, "\t-m tests with monitors (default: FALSE)\n"); 55 PR_fprintf(err, "\t-c tests with cmonitors (default: FALSE)\n"); 56 PR_fprintf(err, "\t-h help\n"); 57 } /* Help */ 58 59 static void PR_CALLBACK T2CMon(void* arg) { 60 PRStatus rv; 61 CMonShared* shared = (CMonShared*)arg; 62 63 PR_CEnterMonitor(&shared->o1); 64 LogNow("T2 waiting 5 seconds on o1", PR_SUCCESS); 65 rv = PR_CWait(&shared->o1, PR_SecondsToInterval(5)); 66 if (PR_SUCCESS == rv) { 67 LogNow("T2 resuming on o1", rv); 68 } else { 69 LogNow("T2 wait failed on o1", rv); 70 } 71 72 rv = PR_CNotify(&shared->o1); 73 if (PR_SUCCESS == rv) { 74 LogNow("T2 notified o1", rv); 75 } else { 76 LogNow("T2 notify on o1 failed", rv); 77 } 78 79 PR_CExitMonitor(&shared->o1); 80 } /* T2CMon */ 81 82 static void PR_CALLBACK T3CMon(void* arg) { 83 PRStatus rv; 84 CMonShared* shared = (CMonShared*)arg; 85 86 PR_CEnterMonitor(&shared->o2); 87 LogNow("T3 waiting 5 seconds on o2", PR_SUCCESS); 88 rv = PR_CWait(&shared->o2, PR_SecondsToInterval(5)); 89 if (PR_SUCCESS == rv) { 90 LogNow("T3 resuming on o2", rv); 91 } else { 92 LogNow("T3 wait failed on o2", rv); 93 } 94 rv = PR_CNotify(&shared->o2); 95 LogNow("T3 notify on o2", rv); 96 PR_CExitMonitor(&shared->o2); 97 98 } /* T3CMon */ 99 100 static CMonShared sharedCM; 101 102 static void T1CMon(void) { 103 PRStatus rv; 104 PRThread *t2, *t3; 105 106 PR_fprintf(err, "\n**********************************\n"); 107 PR_fprintf(err, " CACHED MONITORS\n"); 108 PR_fprintf(err, "**********************************\n"); 109 110 base = PR_IntervalNow(); 111 112 PR_CEnterMonitor(&sharedCM.o1); 113 LogNow("T1 waiting 3 seconds on o1", PR_SUCCESS); 114 rv = PR_CWait(&sharedCM.o1, PR_SecondsToInterval(3)); 115 if (PR_SUCCESS == rv) { 116 LogNow("T1 resuming on o1", rv); 117 } else { 118 LogNow("T1 wait on o1 failed", rv); 119 } 120 PR_CExitMonitor(&sharedCM.o1); 121 122 LogNow("T1 creating T2", PR_SUCCESS); 123 t2 = PR_CreateThread(PR_USER_THREAD, T2CMon, &sharedCM, PR_PRIORITY_NORMAL, 124 PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); 125 126 LogNow("T1 creating T3", PR_SUCCESS); 127 t3 = PR_CreateThread(PR_USER_THREAD, T3CMon, &sharedCM, PR_PRIORITY_NORMAL, 128 PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); 129 130 PR_CEnterMonitor(&sharedCM.o2); 131 LogNow("T1 waiting forever on o2", PR_SUCCESS); 132 rv = PR_CWait(&sharedCM.o2, PR_INTERVAL_NO_TIMEOUT); 133 if (PR_SUCCESS == rv) { 134 LogNow("T1 resuming on o2", rv); 135 } else { 136 LogNow("T1 wait on o2 failed", rv); 137 } 138 PR_CExitMonitor(&sharedCM.o2); 139 140 (void)PR_JoinThread(t2); 141 (void)PR_JoinThread(t3); 142 143 } /* T1CMon */ 144 145 static void PR_CALLBACK T2Mon(void* arg) { 146 PRStatus rv; 147 MonShared* shared = (MonShared*)arg; 148 149 PR_EnterMonitor(shared->o1); 150 LogNow("T2 waiting 5 seconds on o1", PR_SUCCESS); 151 rv = PR_Wait(shared->o1, PR_SecondsToInterval(5)); 152 if (PR_SUCCESS == rv) { 153 LogNow("T2 resuming on o1", rv); 154 } else { 155 LogNow("T2 wait failed on o1", rv); 156 } 157 158 rv = PR_Notify(shared->o1); 159 if (PR_SUCCESS == rv) { 160 LogNow("T2 notified o1", rv); 161 } else { 162 LogNow("T2 notify on o1 failed", rv); 163 } 164 165 PR_ExitMonitor(shared->o1); 166 } /* T2Mon */ 167 168 static void PR_CALLBACK T3Mon(void* arg) { 169 PRStatus rv; 170 MonShared* shared = (MonShared*)arg; 171 172 PR_EnterMonitor(shared->o2); 173 LogNow("T3 waiting 5 seconds on o2", PR_SUCCESS); 174 rv = PR_Wait(shared->o2, PR_SecondsToInterval(5)); 175 if (PR_SUCCESS == rv) { 176 LogNow("T3 resuming on o2", rv); 177 } else { 178 LogNow("T3 wait failed on o2", rv); 179 } 180 rv = PR_Notify(shared->o2); 181 LogNow("T3 notify on o2", rv); 182 PR_ExitMonitor(shared->o2); 183 184 } /* T3Mon */ 185 186 static MonShared sharedM; 187 static void T1Mon(void) { 188 PRStatus rv; 189 PRThread *t2, *t3; 190 191 PR_fprintf(err, "\n**********************************\n"); 192 PR_fprintf(err, " MONITORS\n"); 193 PR_fprintf(err, "**********************************\n"); 194 195 sharedM.o1 = PR_NewMonitor(); 196 sharedM.o2 = PR_NewMonitor(); 197 198 base = PR_IntervalNow(); 199 200 PR_EnterMonitor(sharedM.o1); 201 LogNow("T1 waiting 3 seconds on o1", PR_SUCCESS); 202 rv = PR_Wait(sharedM.o1, PR_SecondsToInterval(3)); 203 if (PR_SUCCESS == rv) { 204 LogNow("T1 resuming on o1", rv); 205 } else { 206 LogNow("T1 wait on o1 failed", rv); 207 } 208 PR_ExitMonitor(sharedM.o1); 209 210 LogNow("T1 creating T2", PR_SUCCESS); 211 t2 = PR_CreateThread(PR_USER_THREAD, T2Mon, &sharedM, PR_PRIORITY_NORMAL, 212 PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); 213 214 LogNow("T1 creating T3", PR_SUCCESS); 215 t3 = PR_CreateThread(PR_USER_THREAD, T3Mon, &sharedM, PR_PRIORITY_NORMAL, 216 PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); 217 218 PR_EnterMonitor(sharedM.o2); 219 LogNow("T1 waiting forever on o2", PR_SUCCESS); 220 rv = PR_Wait(sharedM.o2, PR_INTERVAL_NO_TIMEOUT); 221 if (PR_SUCCESS == rv) { 222 LogNow("T1 resuming on o2", rv); 223 } else { 224 LogNow("T1 wait on o2 failed", rv); 225 } 226 PR_ExitMonitor(sharedM.o2); 227 228 (void)PR_JoinThread(t2); 229 (void)PR_JoinThread(t3); 230 231 PR_DestroyMonitor(sharedM.o1); 232 PR_DestroyMonitor(sharedM.o2); 233 234 } /* T1Mon */ 235 236 static void PR_CALLBACK T2Lock(void* arg) { 237 PRStatus rv; 238 LockShared* shared = (LockShared*)arg; 239 240 PR_Lock(shared->o1); 241 LogNow("T2 waiting 5 seconds on o1", PR_SUCCESS); 242 rv = PR_WaitCondVar(shared->cv1, PR_SecondsToInterval(5)); 243 if (PR_SUCCESS == rv) { 244 LogNow("T2 resuming on o1", rv); 245 } else { 246 LogNow("T2 wait failed on o1", rv); 247 } 248 249 rv = PR_NotifyCondVar(shared->cv1); 250 if (PR_SUCCESS == rv) { 251 LogNow("T2 notified o1", rv); 252 } else { 253 LogNow("T2 notify on o1 failed", rv); 254 } 255 256 PR_Unlock(shared->o1); 257 } /* T2Lock */ 258 259 static void PR_CALLBACK T3Lock(void* arg) { 260 PRStatus rv; 261 LockShared* shared = (LockShared*)arg; 262 263 PR_Lock(shared->o2); 264 LogNow("T3 waiting 5 seconds on o2", PR_SUCCESS); 265 rv = PR_WaitCondVar(shared->cv2, PR_SecondsToInterval(5)); 266 if (PR_SUCCESS == rv) { 267 LogNow("T3 resuming on o2", rv); 268 } else { 269 LogNow("T3 wait failed on o2", rv); 270 } 271 rv = PR_NotifyCondVar(shared->cv2); 272 LogNow("T3 notify on o2", rv); 273 PR_Unlock(shared->o2); 274 275 } /* T3Lock */ 276 277 /* 278 ** Make shared' a static variable for Win16 279 */ 280 static LockShared sharedL; 281 282 static void T1Lock(void) { 283 PRStatus rv; 284 PRThread *t2, *t3; 285 sharedL.o1 = PR_NewLock(); 286 sharedL.o2 = PR_NewLock(); 287 sharedL.cv1 = PR_NewCondVar(sharedL.o1); 288 sharedL.cv2 = PR_NewCondVar(sharedL.o2); 289 290 PR_fprintf(err, "\n**********************************\n"); 291 PR_fprintf(err, " LOCKS\n"); 292 PR_fprintf(err, "**********************************\n"); 293 294 base = PR_IntervalNow(); 295 296 PR_Lock(sharedL.o1); 297 LogNow("T1 waiting 3 seconds on o1", PR_SUCCESS); 298 rv = PR_WaitCondVar(sharedL.cv1, PR_SecondsToInterval(3)); 299 if (PR_SUCCESS == rv) { 300 LogNow("T1 resuming on o1", rv); 301 } else { 302 LogNow("T1 wait on o1 failed", rv); 303 } 304 PR_Unlock(sharedL.o1); 305 306 LogNow("T1 creating T2", PR_SUCCESS); 307 t2 = PR_CreateThread(PR_USER_THREAD, T2Lock, &sharedL, PR_PRIORITY_NORMAL, 308 PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); 309 310 LogNow("T1 creating T3", PR_SUCCESS); 311 t3 = PR_CreateThread(PR_USER_THREAD, T3Lock, &sharedL, PR_PRIORITY_NORMAL, 312 PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); 313 314 PR_Lock(sharedL.o2); 315 LogNow("T1 waiting forever on o2", PR_SUCCESS); 316 rv = PR_WaitCondVar(sharedL.cv2, PR_INTERVAL_NO_TIMEOUT); 317 if (PR_SUCCESS == rv) { 318 LogNow("T1 resuming on o2", rv); 319 } else { 320 LogNow("T1 wait on o2 failed", rv); 321 } 322 PR_Unlock(sharedL.o2); 323 324 (void)PR_JoinThread(t2); 325 (void)PR_JoinThread(t3); 326 327 PR_DestroyLock(sharedL.o1); 328 PR_DestroyLock(sharedL.o2); 329 PR_DestroyCondVar(sharedL.cv1); 330 PR_DestroyCondVar(sharedL.cv2); 331 } /* T1Lock */ 332 333 static PRIntn PR_CALLBACK RealMain(PRIntn argc, char** argv) { 334 PLOptStatus os; 335 PLOptState* opt = PL_CreateOptState(argc, argv, "dhlmc"); 336 PRBool locks = PR_FALSE, monitors = PR_FALSE, cmonitors = PR_FALSE; 337 338 err = PR_GetSpecialFD(PR_StandardError); 339 340 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { 341 if (PL_OPT_BAD == os) { 342 continue; 343 } 344 switch (opt->option) { 345 case 'd': /* debug mode (noop) */ 346 break; 347 case 'l': /* locks */ 348 locks = PR_TRUE; 349 break; 350 case 'm': /* monitors */ 351 monitors = PR_TRUE; 352 break; 353 case 'c': /* cached monitors */ 354 cmonitors = PR_TRUE; 355 break; 356 case 'h': /* needs guidance */ 357 default: 358 Help(); 359 return 2; 360 } 361 } 362 PL_DestroyOptState(opt); 363 364 ml = PR_NewLock(); 365 if (locks) { 366 T1Lock(); 367 } 368 if (monitors) { 369 T1Mon(); 370 } 371 if (cmonitors) { 372 T1CMon(); 373 } 374 375 PR_DestroyLock(ml); 376 377 PR_fprintf(err, "Done!\n"); 378 return 0; 379 } /* main */ 380 381 int main(int argc, char** argv) { 382 PRIntn rv; 383 384 rv = PR_Initialize(RealMain, argc, argv, 0); 385 return rv; 386 } /* main */ 387 /* xnotify.c */