cvar2.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977
  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. ** 1996 - Netscape Communications Corporation
  7. **
  8. ** Name: cvar2.c
  9. **
  10. ** Description: Simple test creates several local and global threads;
  11. ** half use a single,shared condvar, and the
  12. ** other half have their own condvar. The main thread then loops
  13. ** notifying them to wakeup.
  14. **
  15. ** Modification History:
  16. ** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
  17. ** The debug mode will print all of the printfs associated with this test.
  18. ** The regress mode will be the default mode. Since the regress tool limits
  19. ** the output to a one line status:PASS or FAIL,all of the printf statements
  20. ** have been handled with an if (debug_mode) statement.
  21. ***********************************************************************/
  22. #include "nspr.h"
  23. #include "plerror.h"
  24. #include "plgetopt.h"
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. int _debug_on = 0;
  29. #define DPRINTF(arg) if (_debug_on) printf arg
  30. #define DEFAULT_COUNT 100
  31. #define DEFAULT_THREADS 5
  32. PRInt32 count = DEFAULT_COUNT;
  33. typedef struct threadinfo {
  34. PRThread *thread;
  35. PRInt32 id;
  36. PRBool internal;
  37. PRInt32 *tcount;
  38. PRLock *lock;
  39. PRCondVar *cvar;
  40. PRIntervalTime timeout;
  41. PRInt32 loops;
  42. PRLock *exitlock;
  43. PRCondVar *exitcvar;
  44. PRInt32 *exitcount;
  45. } threadinfo;
  46. /*
  47. ** Make exitcount, tcount static. for Win16.
  48. */
  49. static PRInt32 exitcount=0;
  50. static PRInt32 tcount=0;
  51. /* Thread that gets notified; many threads share the same condvar */
  52. void PR_CALLBACK
  53. SharedCondVarThread(void *_info)
  54. {
  55. threadinfo *info = (threadinfo *)_info;
  56. PRInt32 index;
  57. for (index=0; index<info->loops; index++) {
  58. PR_Lock(info->lock);
  59. if (*info->tcount == 0) {
  60. PR_WaitCondVar(info->cvar, info->timeout);
  61. }
  62. #if 0
  63. printf("shared thread %ld notified in loop %ld\n", info->id, index);
  64. #endif
  65. (*info->tcount)--;
  66. PR_Unlock(info->lock);
  67. PR_Lock(info->exitlock);
  68. (*info->exitcount)++;
  69. PR_NotifyCondVar(info->exitcvar);
  70. PR_Unlock(info->exitlock);
  71. }
  72. #if 0
  73. printf("shared thread %ld terminating\n", info->id);
  74. #endif
  75. }
  76. /* Thread that gets notified; no other threads use the same condvar */
  77. void PR_CALLBACK
  78. PrivateCondVarThread(void *_info)
  79. {
  80. threadinfo *info = (threadinfo *)_info;
  81. PRInt32 index;
  82. for (index=0; index<info->loops; index++) {
  83. PR_Lock(info->lock);
  84. if (*info->tcount == 0) {
  85. DPRINTF(("PrivateCondVarThread: thread 0x%lx waiting on cvar = 0x%lx\n",
  86. PR_GetCurrentThread(), info->cvar));
  87. PR_WaitCondVar(info->cvar, info->timeout);
  88. }
  89. #if 0
  90. printf("solo thread %ld notified in loop %ld\n", info->id, index);
  91. #endif
  92. (*info->tcount)--;
  93. PR_Unlock(info->lock);
  94. PR_Lock(info->exitlock);
  95. (*info->exitcount)++;
  96. PR_NotifyCondVar(info->exitcvar);
  97. DPRINTF(("PrivateCondVarThread: thread 0x%lx notified exitcvar = 0x%lx cnt = %ld\n",
  98. PR_GetCurrentThread(), info->exitcvar,(*info->exitcount)));
  99. PR_Unlock(info->exitlock);
  100. }
  101. #if 0
  102. printf("solo thread %ld terminating\n", info->id);
  103. #endif
  104. }
  105. void
  106. CreateTestThread(threadinfo *info,
  107. PRInt32 id,
  108. PRLock *lock,
  109. PRCondVar *cvar,
  110. PRInt32 loops,
  111. PRIntervalTime timeout,
  112. PRInt32 *tcount,
  113. PRLock *exitlock,
  114. PRCondVar *exitcvar,
  115. PRInt32 *exitcount,
  116. PRBool shared,
  117. PRThreadScope scope)
  118. {
  119. info->id = id;
  120. info->internal = (shared) ? PR_FALSE : PR_TRUE;
  121. info->lock = lock;
  122. info->cvar = cvar;
  123. info->loops = loops;
  124. info->timeout = timeout;
  125. info->tcount = tcount;
  126. info->exitlock = exitlock;
  127. info->exitcvar = exitcvar;
  128. info->exitcount = exitcount;
  129. info->thread = PR_CreateThread(
  130. PR_USER_THREAD,
  131. shared?SharedCondVarThread:PrivateCondVarThread,
  132. info,
  133. PR_PRIORITY_NORMAL,
  134. scope,
  135. PR_JOINABLE_THREAD,
  136. 0);
  137. if (!info->thread) {
  138. PL_PrintError("error creating thread\n");
  139. }
  140. }
  141. void
  142. CondVarTestSUU(void *_arg)
  143. {
  144. PRInt32 arg = (PRInt32)_arg;
  145. PRInt32 index, loops;
  146. threadinfo *list;
  147. PRLock *sharedlock;
  148. PRCondVar *sharedcvar;
  149. PRLock *exitlock;
  150. PRCondVar *exitcvar;
  151. exitcount=0;
  152. tcount=0;
  153. list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
  154. sharedlock = PR_NewLock();
  155. sharedcvar = PR_NewCondVar(sharedlock);
  156. exitlock = PR_NewLock();
  157. exitcvar = PR_NewCondVar(exitlock);
  158. /* Create the threads */
  159. for(index=0; index<arg; ) {
  160. CreateTestThread(&list[index],
  161. index,
  162. sharedlock,
  163. sharedcvar,
  164. count,
  165. PR_INTERVAL_NO_TIMEOUT,
  166. &tcount,
  167. exitlock,
  168. exitcvar,
  169. &exitcount,
  170. PR_TRUE,
  171. PR_LOCAL_THREAD);
  172. index++;
  173. DPRINTF(("CondVarTestSUU: created thread 0x%lx\n",list[index].thread));
  174. }
  175. for (loops = 0; loops < count; loops++) {
  176. /* Notify the threads */
  177. for(index=0; index<(arg); index++) {
  178. PR_Lock(list[index].lock);
  179. (*list[index].tcount)++;
  180. PR_NotifyCondVar(list[index].cvar);
  181. PR_Unlock(list[index].lock);
  182. DPRINTF(("PrivateCondVarThread: thread 0x%lx notified cvar = 0x%lx\n",
  183. PR_GetCurrentThread(), list[index].cvar));
  184. }
  185. /* Wait for threads to finish */
  186. PR_Lock(exitlock);
  187. while(exitcount < arg) {
  188. PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
  189. }
  190. PR_ASSERT(exitcount >= arg);
  191. exitcount -= arg;
  192. PR_Unlock(exitlock);
  193. }
  194. /* Join all the threads */
  195. for(index=0; index<(arg); index++) {
  196. PR_JoinThread(list[index].thread);
  197. }
  198. PR_DestroyCondVar(sharedcvar);
  199. PR_DestroyLock(sharedlock);
  200. PR_DestroyCondVar(exitcvar);
  201. PR_DestroyLock(exitlock);
  202. PR_DELETE(list);
  203. }
  204. void
  205. CondVarTestSUK(void *_arg)
  206. {
  207. PRInt32 arg = (PRInt32)_arg;
  208. PRInt32 index, loops;
  209. threadinfo *list;
  210. PRLock *sharedlock;
  211. PRCondVar *sharedcvar;
  212. PRLock *exitlock;
  213. PRCondVar *exitcvar;
  214. exitcount=0;
  215. tcount=0;
  216. list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
  217. sharedlock = PR_NewLock();
  218. sharedcvar = PR_NewCondVar(sharedlock);
  219. exitlock = PR_NewLock();
  220. exitcvar = PR_NewCondVar(exitlock);
  221. /* Create the threads */
  222. for(index=0; index<arg; ) {
  223. CreateTestThread(&list[index],
  224. index,
  225. sharedlock,
  226. sharedcvar,
  227. count,
  228. PR_INTERVAL_NO_TIMEOUT,
  229. &tcount,
  230. exitlock,
  231. exitcvar,
  232. &exitcount,
  233. PR_TRUE,
  234. PR_GLOBAL_THREAD);
  235. index++;
  236. }
  237. for (loops = 0; loops < count; loops++) {
  238. /* Notify the threads */
  239. for(index=0; index<(arg); index++) {
  240. PR_Lock(list[index].lock);
  241. (*list[index].tcount)++;
  242. PR_NotifyCondVar(list[index].cvar);
  243. PR_Unlock(list[index].lock);
  244. }
  245. #if 0
  246. printf("wait for threads to be done\n");
  247. #endif
  248. /* Wait for threads to finish */
  249. PR_Lock(exitlock);
  250. while(exitcount < arg) {
  251. PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
  252. }
  253. PR_ASSERT(exitcount >= arg);
  254. exitcount -= arg;
  255. PR_Unlock(exitlock);
  256. #if 0
  257. printf("threads ready\n");
  258. #endif
  259. }
  260. /* Join all the threads */
  261. for(index=0; index<(arg); index++) {
  262. PR_JoinThread(list[index].thread);
  263. }
  264. PR_DestroyCondVar(sharedcvar);
  265. PR_DestroyLock(sharedlock);
  266. PR_DestroyCondVar(exitcvar);
  267. PR_DestroyLock(exitlock);
  268. PR_DELETE(list);
  269. }
  270. void
  271. CondVarTestPUU(void *_arg)
  272. {
  273. PRInt32 arg = (PRInt32)_arg;
  274. PRInt32 index, loops;
  275. threadinfo *list;
  276. PRLock *sharedlock;
  277. PRCondVar *sharedcvar;
  278. PRLock *exitlock;
  279. PRCondVar *exitcvar;
  280. PRInt32 *tcount, *saved_tcount;
  281. exitcount=0;
  282. list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
  283. saved_tcount = tcount = (PRInt32 *)PR_CALLOC(sizeof(*tcount) * (arg * 4));
  284. sharedlock = PR_NewLock();
  285. sharedcvar = PR_NewCondVar(sharedlock);
  286. exitlock = PR_NewLock();
  287. exitcvar = PR_NewCondVar(exitlock);
  288. /* Create the threads */
  289. for(index=0; index<arg; ) {
  290. list[index].lock = PR_NewLock();
  291. list[index].cvar = PR_NewCondVar(list[index].lock);
  292. CreateTestThread(&list[index],
  293. index,
  294. list[index].lock,
  295. list[index].cvar,
  296. count,
  297. PR_INTERVAL_NO_TIMEOUT,
  298. tcount,
  299. exitlock,
  300. exitcvar,
  301. &exitcount,
  302. PR_FALSE,
  303. PR_LOCAL_THREAD);
  304. DPRINTF(("CondVarTestPUU: created thread 0x%lx\n",list[index].thread));
  305. index++;
  306. tcount++;
  307. }
  308. for (loops = 0; loops < count; loops++) {
  309. /* Notify the threads */
  310. for(index=0; index<(arg); index++) {
  311. PR_Lock(list[index].lock);
  312. (*list[index].tcount)++;
  313. PR_NotifyCondVar(list[index].cvar);
  314. PR_Unlock(list[index].lock);
  315. }
  316. PR_Lock(exitlock);
  317. /* Wait for threads to finish */
  318. while(exitcount < arg) {
  319. DPRINTF(("CondVarTestPUU: thread 0x%lx waiting on exitcvar = 0x%lx cnt = %ld\n",
  320. PR_GetCurrentThread(), exitcvar, exitcount));
  321. PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
  322. }
  323. PR_ASSERT(exitcount >= arg);
  324. exitcount -= arg;
  325. PR_Unlock(exitlock);
  326. }
  327. /* Join all the threads */
  328. for(index=0; index<(arg); index++) {
  329. DPRINTF(("CondVarTestPUU: joining thread 0x%lx\n",list[index].thread));
  330. PR_JoinThread(list[index].thread);
  331. if (list[index].internal) {
  332. PR_Lock(list[index].lock);
  333. PR_DestroyCondVar(list[index].cvar);
  334. PR_Unlock(list[index].lock);
  335. PR_DestroyLock(list[index].lock);
  336. }
  337. }
  338. PR_DestroyCondVar(sharedcvar);
  339. PR_DestroyLock(sharedlock);
  340. PR_DestroyCondVar(exitcvar);
  341. PR_DestroyLock(exitlock);
  342. PR_DELETE(list);
  343. PR_DELETE(saved_tcount);
  344. }
  345. void
  346. CondVarTestPUK(void *_arg)
  347. {
  348. PRInt32 arg = (PRInt32)_arg;
  349. PRInt32 index, loops;
  350. threadinfo *list;
  351. PRLock *sharedlock;
  352. PRCondVar *sharedcvar;
  353. PRLock *exitlock;
  354. PRCondVar *exitcvar;
  355. PRInt32 *tcount, *saved_tcount;
  356. exitcount=0;
  357. list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
  358. saved_tcount = tcount = (PRInt32 *)PR_CALLOC(sizeof(*tcount) * (arg * 4));
  359. sharedlock = PR_NewLock();
  360. sharedcvar = PR_NewCondVar(sharedlock);
  361. exitlock = PR_NewLock();
  362. exitcvar = PR_NewCondVar(exitlock);
  363. /* Create the threads */
  364. for(index=0; index<arg; ) {
  365. list[index].lock = PR_NewLock();
  366. list[index].cvar = PR_NewCondVar(list[index].lock);
  367. CreateTestThread(&list[index],
  368. index,
  369. list[index].lock,
  370. list[index].cvar,
  371. count,
  372. PR_INTERVAL_NO_TIMEOUT,
  373. tcount,
  374. exitlock,
  375. exitcvar,
  376. &exitcount,
  377. PR_FALSE,
  378. PR_GLOBAL_THREAD);
  379. index++;
  380. tcount++;
  381. }
  382. for (loops = 0; loops < count; loops++) {
  383. /* Notify the threads */
  384. for(index=0; index<(arg); index++) {
  385. PR_Lock(list[index].lock);
  386. (*list[index].tcount)++;
  387. PR_NotifyCondVar(list[index].cvar);
  388. PR_Unlock(list[index].lock);
  389. }
  390. /* Wait for threads to finish */
  391. PR_Lock(exitlock);
  392. while(exitcount < arg) {
  393. PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
  394. }
  395. PR_ASSERT(exitcount >= arg);
  396. exitcount -= arg;
  397. PR_Unlock(exitlock);
  398. }
  399. /* Join all the threads */
  400. for(index=0; index<(arg); index++) {
  401. PR_JoinThread(list[index].thread);
  402. if (list[index].internal) {
  403. PR_Lock(list[index].lock);
  404. PR_DestroyCondVar(list[index].cvar);
  405. PR_Unlock(list[index].lock);
  406. PR_DestroyLock(list[index].lock);
  407. }
  408. }
  409. PR_DestroyCondVar(sharedcvar);
  410. PR_DestroyLock(sharedlock);
  411. PR_DestroyCondVar(exitcvar);
  412. PR_DestroyLock(exitlock);
  413. PR_DELETE(list);
  414. PR_DELETE(saved_tcount);
  415. }
  416. void
  417. CondVarTest(void *_arg)
  418. {
  419. PRInt32 arg = (PRInt32)_arg;
  420. PRInt32 index, loops;
  421. threadinfo *list;
  422. PRLock *sharedlock;
  423. PRCondVar *sharedcvar;
  424. PRLock *exitlock;
  425. PRCondVar *exitcvar;
  426. PRInt32 *ptcount, *saved_ptcount;
  427. exitcount=0;
  428. tcount=0;
  429. list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
  430. saved_ptcount = ptcount = (PRInt32 *)PR_CALLOC(sizeof(*ptcount) * (arg * 4));
  431. sharedlock = PR_NewLock();
  432. sharedcvar = PR_NewCondVar(sharedlock);
  433. exitlock = PR_NewLock();
  434. exitcvar = PR_NewCondVar(exitlock);
  435. /* Create the threads */
  436. for(index=0; index<arg*4; ) {
  437. CreateTestThread(&list[index],
  438. index,
  439. sharedlock,
  440. sharedcvar,
  441. count,
  442. PR_INTERVAL_NO_TIMEOUT,
  443. &tcount,
  444. exitlock,
  445. exitcvar,
  446. &exitcount,
  447. PR_TRUE,
  448. PR_LOCAL_THREAD);
  449. index++;
  450. CreateTestThread(&list[index],
  451. index,
  452. sharedlock,
  453. sharedcvar,
  454. count,
  455. PR_INTERVAL_NO_TIMEOUT,
  456. &tcount,
  457. exitlock,
  458. exitcvar,
  459. &exitcount,
  460. PR_TRUE,
  461. PR_GLOBAL_THREAD);
  462. index++;
  463. list[index].lock = PR_NewLock();
  464. list[index].cvar = PR_NewCondVar(list[index].lock);
  465. CreateTestThread(&list[index],
  466. index,
  467. list[index].lock,
  468. list[index].cvar,
  469. count,
  470. PR_INTERVAL_NO_TIMEOUT,
  471. ptcount,
  472. exitlock,
  473. exitcvar,
  474. &exitcount,
  475. PR_FALSE,
  476. PR_LOCAL_THREAD);
  477. index++;
  478. ptcount++;
  479. list[index].lock = PR_NewLock();
  480. list[index].cvar = PR_NewCondVar(list[index].lock);
  481. CreateTestThread(&list[index],
  482. index,
  483. list[index].lock,
  484. list[index].cvar,
  485. count,
  486. PR_INTERVAL_NO_TIMEOUT,
  487. ptcount,
  488. exitlock,
  489. exitcvar,
  490. &exitcount,
  491. PR_FALSE,
  492. PR_GLOBAL_THREAD);
  493. index++;
  494. ptcount++;
  495. }
  496. for (loops = 0; loops < count; loops++) {
  497. /* Notify the threads */
  498. for(index=0; index<(arg*4); index++) {
  499. PR_Lock(list[index].lock);
  500. (*list[index].tcount)++;
  501. PR_NotifyCondVar(list[index].cvar);
  502. PR_Unlock(list[index].lock);
  503. }
  504. #if 0
  505. printf("wait for threads done\n");
  506. #endif
  507. /* Wait for threads to finish */
  508. PR_Lock(exitlock);
  509. while(exitcount < arg*4) {
  510. PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
  511. }
  512. PR_ASSERT(exitcount >= arg*4);
  513. exitcount -= arg*4;
  514. PR_Unlock(exitlock);
  515. #if 0
  516. printf("threads ready\n");
  517. #endif
  518. }
  519. /* Join all the threads */
  520. for(index=0; index<(arg*4); index++) {
  521. PR_JoinThread(list[index].thread);
  522. if (list[index].internal) {
  523. PR_Lock(list[index].lock);
  524. PR_DestroyCondVar(list[index].cvar);
  525. PR_Unlock(list[index].lock);
  526. PR_DestroyLock(list[index].lock);
  527. }
  528. }
  529. PR_DestroyCondVar(sharedcvar);
  530. PR_DestroyLock(sharedlock);
  531. PR_DestroyCondVar(exitcvar);
  532. PR_DestroyLock(exitlock);
  533. PR_DELETE(list);
  534. PR_DELETE(saved_ptcount);
  535. }
  536. void
  537. CondVarTimeoutTest(void *_arg)
  538. {
  539. PRInt32 arg = (PRInt32)_arg;
  540. PRInt32 index, loops;
  541. threadinfo *list;
  542. PRLock *sharedlock;
  543. PRCondVar *sharedcvar;
  544. PRLock *exitlock;
  545. PRCondVar *exitcvar;
  546. list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
  547. sharedlock = PR_NewLock();
  548. sharedcvar = PR_NewCondVar(sharedlock);
  549. exitlock = PR_NewLock();
  550. exitcvar = PR_NewCondVar(exitlock);
  551. /* Create the threads */
  552. for(index=0; index<arg*4; ) {
  553. CreateTestThread(&list[index],
  554. index,
  555. sharedlock,
  556. sharedcvar,
  557. count,
  558. PR_MillisecondsToInterval(50),
  559. &tcount,
  560. exitlock,
  561. exitcvar,
  562. &exitcount,
  563. PR_TRUE,
  564. PR_LOCAL_THREAD);
  565. index++;
  566. CreateTestThread(&list[index],
  567. index,
  568. sharedlock,
  569. sharedcvar,
  570. count,
  571. PR_MillisecondsToInterval(50),
  572. &tcount,
  573. exitlock,
  574. exitcvar,
  575. &exitcount,
  576. PR_TRUE,
  577. PR_GLOBAL_THREAD);
  578. index++;
  579. list[index].lock = PR_NewLock();
  580. list[index].cvar = PR_NewCondVar(list[index].lock);
  581. CreateTestThread(&list[index],
  582. index,
  583. list[index].lock,
  584. list[index].cvar,
  585. count,
  586. PR_MillisecondsToInterval(50),
  587. &tcount,
  588. exitlock,
  589. exitcvar,
  590. &exitcount,
  591. PR_FALSE,
  592. PR_LOCAL_THREAD);
  593. index++;
  594. list[index].lock = PR_NewLock();
  595. list[index].cvar = PR_NewCondVar(list[index].lock);
  596. CreateTestThread(&list[index],
  597. index,
  598. list[index].lock,
  599. list[index].cvar,
  600. count,
  601. PR_MillisecondsToInterval(50),
  602. &tcount,
  603. exitlock,
  604. exitcvar,
  605. &exitcount,
  606. PR_FALSE,
  607. PR_GLOBAL_THREAD);
  608. index++;
  609. }
  610. for (loops = 0; loops < count; loops++) {
  611. /* Wait for threads to finish */
  612. PR_Lock(exitlock);
  613. while(exitcount < arg*4) {
  614. PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
  615. }
  616. PR_ASSERT(exitcount >= arg*4);
  617. exitcount -= arg*4;
  618. PR_Unlock(exitlock);
  619. }
  620. /* Join all the threads */
  621. for(index=0; index<(arg*4); index++) {
  622. PR_JoinThread(list[index].thread);
  623. if (list[index].internal) {
  624. PR_Lock(list[index].lock);
  625. PR_DestroyCondVar(list[index].cvar);
  626. PR_Unlock(list[index].lock);
  627. PR_DestroyLock(list[index].lock);
  628. }
  629. }
  630. PR_DestroyCondVar(sharedcvar);
  631. PR_DestroyLock(sharedlock);
  632. PR_DestroyCondVar(exitcvar);
  633. PR_DestroyLock(exitlock);
  634. PR_DELETE(list);
  635. }
  636. void
  637. CondVarMixedTest(void *_arg)
  638. {
  639. PRInt32 arg = (PRInt32)_arg;
  640. PRInt32 index, loops;
  641. threadinfo *list;
  642. PRLock *sharedlock;
  643. PRCondVar *sharedcvar;
  644. PRLock *exitlock;
  645. PRCondVar *exitcvar;
  646. PRInt32 *ptcount;
  647. exitcount=0;
  648. tcount=0;
  649. list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4));
  650. ptcount = (PRInt32 *)PR_CALLOC(sizeof(*ptcount) * (arg * 4));
  651. sharedlock = PR_NewLock();
  652. sharedcvar = PR_NewCondVar(sharedlock);
  653. exitlock = PR_NewLock();
  654. exitcvar = PR_NewCondVar(exitlock);
  655. /* Create the threads */
  656. for(index=0; index<arg*4; ) {
  657. CreateTestThread(&list[index],
  658. index,
  659. sharedlock,
  660. sharedcvar,
  661. count,
  662. PR_MillisecondsToInterval(50),
  663. &tcount,
  664. exitlock,
  665. exitcvar,
  666. &exitcount,
  667. PR_TRUE,
  668. PR_LOCAL_THREAD);
  669. index++;
  670. CreateTestThread(&list[index],
  671. index,
  672. sharedlock,
  673. sharedcvar,
  674. count,
  675. PR_MillisecondsToInterval(50),
  676. &tcount,
  677. exitlock,
  678. exitcvar,
  679. &exitcount,
  680. PR_TRUE,
  681. PR_GLOBAL_THREAD);
  682. index++;
  683. list[index].lock = PR_NewLock();
  684. list[index].cvar = PR_NewCondVar(list[index].lock);
  685. CreateTestThread(&list[index],
  686. index,
  687. list[index].lock,
  688. list[index].cvar,
  689. count,
  690. PR_MillisecondsToInterval(50),
  691. ptcount,
  692. exitlock,
  693. exitcvar,
  694. &exitcount,
  695. PR_FALSE,
  696. PR_LOCAL_THREAD);
  697. index++;
  698. ptcount++;
  699. list[index].lock = PR_NewLock();
  700. list[index].cvar = PR_NewCondVar(list[index].lock);
  701. CreateTestThread(&list[index],
  702. index,
  703. list[index].lock,
  704. list[index].cvar,
  705. count,
  706. PR_MillisecondsToInterval(50),
  707. ptcount,
  708. exitlock,
  709. exitcvar,
  710. &exitcount,
  711. PR_FALSE,
  712. PR_GLOBAL_THREAD);
  713. index++;
  714. ptcount++;
  715. }
  716. /* Notify every 3rd thread */
  717. for (loops = 0; loops < count; loops++) {
  718. /* Notify the threads */
  719. for(index=0; index<(arg*4); index+=3) {
  720. PR_Lock(list[index].lock);
  721. *list[index].tcount++;
  722. PR_NotifyCondVar(list[index].cvar);
  723. PR_Unlock(list[index].lock);
  724. }
  725. /* Wait for threads to finish */
  726. PR_Lock(exitlock);
  727. while(exitcount < arg*4) {
  728. PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60));
  729. }
  730. PR_ASSERT(exitcount >= arg*4);
  731. exitcount -= arg*4;
  732. PR_Unlock(exitlock);
  733. }
  734. /* Join all the threads */
  735. for(index=0; index<(arg*4); index++) {
  736. PR_JoinThread(list[index].thread);
  737. if (list[index].internal) {
  738. PR_Lock(list[index].lock);
  739. PR_DestroyCondVar(list[index].cvar);
  740. PR_Unlock(list[index].lock);
  741. PR_DestroyLock(list[index].lock);
  742. }
  743. }
  744. PR_DestroyCondVar(sharedcvar);
  745. PR_DestroyLock(sharedlock);
  746. PR_DELETE(list);
  747. }
  748. void
  749. CondVarCombinedTest(void *arg)
  750. {
  751. PRThread *threads[3];
  752. threads[0] = PR_CreateThread(PR_USER_THREAD,
  753. CondVarTest,
  754. (void *)arg,
  755. PR_PRIORITY_NORMAL,
  756. PR_GLOBAL_THREAD,
  757. PR_JOINABLE_THREAD,
  758. 0);
  759. threads[1] = PR_CreateThread(PR_USER_THREAD,
  760. CondVarTimeoutTest,
  761. (void *)arg,
  762. PR_PRIORITY_NORMAL,
  763. PR_GLOBAL_THREAD,
  764. PR_JOINABLE_THREAD,
  765. 0);
  766. threads[2] = PR_CreateThread(PR_USER_THREAD,
  767. CondVarMixedTest,
  768. (void *)arg,
  769. PR_PRIORITY_NORMAL,
  770. PR_GLOBAL_THREAD,
  771. PR_JOINABLE_THREAD,
  772. 0);
  773. PR_JoinThread(threads[0]);
  774. PR_JoinThread(threads[1]);
  775. PR_JoinThread(threads[2]);
  776. }
  777. /************************************************************************/
  778. static void Measure(void (*func)(void *), PRInt32 arg, const char *msg)
  779. {
  780. PRIntervalTime start, stop;
  781. double d;
  782. start = PR_IntervalNow();
  783. (*func)((void *)arg);
  784. stop = PR_IntervalNow();
  785. d = (double)PR_IntervalToMicroseconds(stop - start);
  786. printf("%40s: %6.2f usec\n", msg, d / count);
  787. }
  788. static PRIntn PR_CALLBACK RealMain(int argc, char **argv)
  789. {
  790. PRInt32 threads, default_threads = DEFAULT_THREADS;
  791. PLOptStatus os;
  792. PLOptState *opt = PL_CreateOptState(argc, argv, "vc:t:");
  793. while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
  794. {
  795. if (PL_OPT_BAD == os) {
  796. continue;
  797. }
  798. switch (opt->option)
  799. {
  800. case 'v': /* debug mode */
  801. _debug_on = 1;
  802. break;
  803. case 'c': /* loop counter */
  804. count = atoi(opt->value);
  805. break;
  806. case 't': /* number of threads involved */
  807. default_threads = atoi(opt->value);
  808. break;
  809. default:
  810. break;
  811. }
  812. }
  813. PL_DestroyOptState(opt);
  814. if (0 == count) {
  815. count = DEFAULT_COUNT;
  816. }
  817. if (0 == default_threads) {
  818. default_threads = DEFAULT_THREADS;
  819. }
  820. printf("\n\
  821. CondVar Test: \n\
  822. \n\
  823. Simple test creates several local and global threads; half use a single,\n\
  824. shared condvar, and the other half have their own condvar. The main \n\
  825. thread then loops notifying them to wakeup. \n\
  826. \n\
  827. The timeout test is very similar except that the threads are not \n\
  828. notified. They will all wakeup on a 1 second timeout. \n\
  829. \n\
  830. The mixed test combines the simple test and the timeout test; every \n\
  831. third thread is notified, the other threads are expected to timeout \n\
  832. correctly. \n\
  833. \n\
  834. Lastly, the combined test creates a thread for each of the above three \n\
  835. cases and they all run simultaneously. \n\
  836. \n\
  837. This test is run with %d, %d, %d, and %d threads of each type.\n\n",
  838. default_threads, default_threads*2, default_threads*3, default_threads*4);
  839. PR_SetConcurrency(2);
  840. for (threads = default_threads; threads < default_threads*5; threads+=default_threads) {
  841. printf("\n%ld Thread tests\n", threads);
  842. Measure(CondVarTestSUU, threads, "Condvar simple test shared UU");
  843. Measure(CondVarTestSUK, threads, "Condvar simple test shared UK");
  844. Measure(CondVarTestPUU, threads, "Condvar simple test priv UU");
  845. Measure(CondVarTestPUK, threads, "Condvar simple test priv UK");
  846. Measure(CondVarTest, threads, "Condvar simple test All");
  847. Measure(CondVarTimeoutTest, threads, "Condvar timeout test");
  848. #if 0
  849. Measure(CondVarMixedTest, threads, "Condvar mixed timeout test");
  850. Measure(CondVarCombinedTest, threads, "Combined condvar test");
  851. #endif
  852. }
  853. printf("PASS\n");
  854. return 0;
  855. }
  856. int main(int argc, char **argv)
  857. {
  858. PRIntn rv;
  859. PR_STDIO_INIT();
  860. rv = PR_Initialize(RealMain, argc, argv, 0);
  861. return rv;
  862. } /* main */