cltsrv.c 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272
  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. *
  7. * Notes:
  8. * [1] lth. The call to Sleep() is a hack to get the test case to run
  9. * on Windows 95. Without it, the test case fails with an error
  10. * WSAECONNRESET following a recv() call. The error is caused by the
  11. * server side thread termination without a shutdown() or closesocket()
  12. * call. Windows docmunentation suggests that this is predicted
  13. * behavior; that other platforms get away with it is ... serindipity.
  14. * The test case should shutdown() or closesocket() before
  15. * thread termination. I didn't have time to figure out where or how
  16. * to do it. The Sleep() call inserts enough delay to allow the
  17. * client side to recv() all his data before the server side thread
  18. * terminates. Whew! ...
  19. *
  20. ** Modification History:
  21. * 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
  22. * The debug mode will print all of the printfs associated with this test.
  23. * The regress mode will be the default mode. Since the regress tool limits
  24. * the output to a one line status:PASS or FAIL,all of the printf statements
  25. * have been handled with an if (debug_mode) statement.
  26. */
  27. #include "prclist.h"
  28. #include "prcvar.h"
  29. #include "prerror.h"
  30. #include "prinit.h"
  31. #include "prinrval.h"
  32. #include "prio.h"
  33. #include "prlock.h"
  34. #include "prlog.h"
  35. #include "prtime.h"
  36. #include "prmem.h"
  37. #include "prnetdb.h"
  38. #include "prprf.h"
  39. #include "prthread.h"
  40. #include "pprio.h"
  41. #include "primpl.h"
  42. #include "plstr.h"
  43. #include "plerror.h"
  44. #include "plgetopt.h"
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #if defined(XP_UNIX)
  48. #include <math.h>
  49. #endif
  50. /*
  51. ** This is the beginning of the test
  52. */
  53. #define RECV_FLAGS 0
  54. #define SEND_FLAGS 0
  55. #define DEFAULT_LOW 0
  56. #define DEFAULT_HIGH 0
  57. #define BUFFER_SIZE 1024
  58. #define DEFAULT_BACKLOG 5
  59. #ifdef DEBUG
  60. #define PORT_INC_DO +100
  61. #else
  62. #define PORT_INC_DO
  63. #endif
  64. #ifdef IS_64
  65. #define PORT_INC_3264 +200
  66. #else
  67. #define PORT_INC_3264
  68. #endif
  69. #define DEFAULT_PORT 12849 PORT_INC_DO PORT_INC_3264
  70. #define DEFAULT_CLIENTS 1
  71. #define ALLOWED_IN_ACCEPT 1
  72. #define DEFAULT_CLIPPING 1000
  73. #define DEFAULT_WORKERS_MIN 1
  74. #define DEFAULT_WORKERS_MAX 1
  75. #define DEFAULT_SERVER "localhost"
  76. #define DEFAULT_EXECUTION_TIME 10
  77. #define DEFAULT_CLIENT_TIMEOUT 4000
  78. #define DEFAULT_SERVER_TIMEOUT 4000
  79. #define DEFAULT_SERVER_PRIORITY PR_PRIORITY_HIGH
  80. typedef enum CSState_e {cs_init, cs_run, cs_stop, cs_exit} CSState_t;
  81. static void PR_CALLBACK Worker(void *arg);
  82. typedef struct CSPool_s CSPool_t;
  83. typedef struct CSWorker_s CSWorker_t;
  84. typedef struct CSServer_s CSServer_t;
  85. typedef enum Verbosity
  86. {
  87. TEST_LOG_ALWAYS,
  88. TEST_LOG_ERROR,
  89. TEST_LOG_WARNING,
  90. TEST_LOG_NOTICE,
  91. TEST_LOG_INFO,
  92. TEST_LOG_STATUS,
  93. TEST_LOG_VERBOSE
  94. } Verbosity;
  95. static PRInt32 domain = AF_INET;
  96. static PRInt32 protocol = 6; /* TCP */
  97. static PRFileDesc *debug_out = NULL;
  98. static PRBool debug_mode = PR_FALSE;
  99. static PRBool pthread_stats = PR_FALSE;
  100. static Verbosity verbosity = TEST_LOG_ALWAYS;
  101. static PRThreadScope thread_scope = PR_LOCAL_THREAD;
  102. struct CSWorker_s
  103. {
  104. PRCList element; /* list of the server's workers */
  105. PRThread *thread; /* this worker objects thread */
  106. CSServer_t *server; /* back pointer to server structure */
  107. };
  108. struct CSPool_s
  109. {
  110. PRCondVar *exiting;
  111. PRCondVar *acceptComplete;
  112. PRUint32 accepting, active, workers;
  113. };
  114. struct CSServer_s
  115. {
  116. PRCList list; /* head of worker list */
  117. PRLock *ml;
  118. PRThread *thread; /* the main server thread */
  119. PRCondVar *stateChange;
  120. PRUint16 port; /* port we're listening on */
  121. PRUint32 backlog; /* size of our listener backlog */
  122. PRFileDesc *listener; /* the fd accepting connections */
  123. CSPool_t pool; /* statistics on worker threads */
  124. CSState_t state; /* the server's state */
  125. struct /* controlling worker counts */
  126. {
  127. PRUint32 minimum, maximum, accepting;
  128. } workers;
  129. /* statistics */
  130. PRIntervalTime started, stopped;
  131. PRUint32 operations, bytesTransferred;
  132. };
  133. typedef struct CSDescriptor_s
  134. {
  135. PRInt32 size; /* size of transfer */
  136. char filename[60]; /* filename, null padded */
  137. } CSDescriptor_t;
  138. typedef struct CSClient_s
  139. {
  140. PRLock *ml;
  141. PRThread *thread;
  142. PRCondVar *stateChange;
  143. PRNetAddr serverAddress;
  144. CSState_t state;
  145. /* statistics */
  146. PRIntervalTime started, stopped;
  147. PRUint32 operations, bytesTransferred;
  148. } CSClient_t;
  149. #define TEST_LOG(l, p, a) \
  150. do { \
  151. if (debug_mode || (p <= verbosity)) printf a; \
  152. } while (0)
  153. PRLogModuleInfo *cltsrv_log_file = NULL;
  154. #define MY_ASSERT(_expr) \
  155. ((_expr)?((void)0):_MY_Assert(# _expr,__FILE__,__LINE__))
  156. #define TEST_ASSERT(_expr) \
  157. ((_expr)?((void)0):_MY_Assert(# _expr,__FILE__,__LINE__))
  158. static void _MY_Assert(const char *s, const char *file, PRIntn ln)
  159. {
  160. PL_PrintError(NULL);
  161. PR_Assert(s, file, ln);
  162. } /* _MY_Assert */
  163. static PRBool Aborted(PRStatus rv)
  164. {
  165. return ((PR_FAILURE == rv) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) ?
  166. PR_TRUE : PR_FALSE;
  167. }
  168. static void TimeOfDayMessage(const char *msg, PRThread* me)
  169. {
  170. char buffer[100];
  171. PRExplodedTime tod;
  172. PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &tod);
  173. (void)PR_FormatTime(buffer, sizeof(buffer), "%H:%M:%S", &tod);
  174. TEST_LOG(
  175. cltsrv_log_file, TEST_LOG_ALWAYS,
  176. ("%s(0x%p): %s\n", msg, me, buffer));
  177. } /* TimeOfDayMessage */
  178. static void PR_CALLBACK Client(void *arg)
  179. {
  180. PRStatus rv;
  181. PRIntn index;
  182. char buffer[1024];
  183. PRFileDesc *fd = NULL;
  184. PRUintn clipping = DEFAULT_CLIPPING;
  185. PRThread *me = PR_GetCurrentThread();
  186. CSClient_t *client = (CSClient_t*)arg;
  187. CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t);
  188. PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_CLIENT_TIMEOUT);
  189. for (index = 0; index < sizeof(buffer); ++index) {
  190. buffer[index] = (char)index;
  191. }
  192. client->started = PR_IntervalNow();
  193. PR_Lock(client->ml);
  194. client->state = cs_run;
  195. PR_NotifyCondVar(client->stateChange);
  196. PR_Unlock(client->ml);
  197. TimeOfDayMessage("Client started at", me);
  198. while (cs_run == client->state)
  199. {
  200. PRInt32 bytes, descbytes, filebytes, netbytes;
  201. (void)PR_NetAddrToString(&client->serverAddress, buffer, sizeof(buffer));
  202. TEST_LOG(cltsrv_log_file, TEST_LOG_INFO,
  203. ("\tClient(0x%p): connecting to server at %s\n", me, buffer));
  204. fd = PR_Socket(domain, SOCK_STREAM, protocol);
  205. TEST_ASSERT(NULL != fd);
  206. rv = PR_Connect(fd, &client->serverAddress, timeout);
  207. if (PR_FAILURE == rv)
  208. {
  209. TEST_LOG(
  210. cltsrv_log_file, TEST_LOG_ERROR,
  211. ("\tClient(0x%p): conection failed (%d, %d)\n",
  212. me, PR_GetError(), PR_GetOSError()));
  213. goto aborted;
  214. }
  215. memset(descriptor, 0, sizeof(*descriptor));
  216. descriptor->size = PR_htonl(descbytes = rand() % clipping);
  217. PR_snprintf(
  218. descriptor->filename, sizeof(descriptor->filename),
  219. "CS%p%p-%p.dat", client->started, me, client->operations);
  220. TEST_LOG(
  221. cltsrv_log_file, TEST_LOG_VERBOSE,
  222. ("\tClient(0x%p): sending descriptor for %u bytes\n", me, descbytes));
  223. bytes = PR_Send(
  224. fd, descriptor, sizeof(*descriptor), SEND_FLAGS, timeout);
  225. if (sizeof(CSDescriptor_t) != bytes)
  226. {
  227. if (Aborted(PR_FAILURE)) {
  228. goto aborted;
  229. }
  230. if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  231. {
  232. TEST_LOG(
  233. cltsrv_log_file, TEST_LOG_ERROR,
  234. ("\tClient(0x%p): send descriptor timeout\n", me));
  235. goto retry;
  236. }
  237. }
  238. TEST_ASSERT(sizeof(*descriptor) == bytes);
  239. netbytes = 0;
  240. while (netbytes < descbytes)
  241. {
  242. filebytes = sizeof(buffer);
  243. if ((descbytes - netbytes) < filebytes) {
  244. filebytes = descbytes - netbytes;
  245. }
  246. TEST_LOG(
  247. cltsrv_log_file, TEST_LOG_VERBOSE,
  248. ("\tClient(0x%p): sending %d bytes\n", me, filebytes));
  249. bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout);
  250. if (filebytes != bytes)
  251. {
  252. if (Aborted(PR_FAILURE)) {
  253. goto aborted;
  254. }
  255. if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  256. {
  257. TEST_LOG(
  258. cltsrv_log_file, TEST_LOG_ERROR,
  259. ("\tClient(0x%p): send data timeout\n", me));
  260. goto retry;
  261. }
  262. }
  263. TEST_ASSERT(bytes == filebytes);
  264. netbytes += bytes;
  265. }
  266. filebytes = 0;
  267. while (filebytes < descbytes)
  268. {
  269. netbytes = sizeof(buffer);
  270. if ((descbytes - filebytes) < netbytes) {
  271. netbytes = descbytes - filebytes;
  272. }
  273. TEST_LOG(
  274. cltsrv_log_file, TEST_LOG_VERBOSE,
  275. ("\tClient(0x%p): receiving %d bytes\n", me, netbytes));
  276. bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout);
  277. if (-1 == bytes)
  278. {
  279. if (Aborted(PR_FAILURE))
  280. {
  281. TEST_LOG(
  282. cltsrv_log_file, TEST_LOG_ERROR,
  283. ("\tClient(0x%p): receive data aborted\n", me));
  284. goto aborted;
  285. }
  286. else if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  287. TEST_LOG(
  288. cltsrv_log_file, TEST_LOG_ERROR,
  289. ("\tClient(0x%p): receive data timeout\n", me));
  290. else
  291. TEST_LOG(
  292. cltsrv_log_file, TEST_LOG_ERROR,
  293. ("\tClient(0x%p): receive error (%d, %d)\n",
  294. me, PR_GetError(), PR_GetOSError()));
  295. goto retry;
  296. }
  297. if (0 == bytes)
  298. {
  299. TEST_LOG(
  300. cltsrv_log_file, TEST_LOG_ERROR,
  301. ("\t\tClient(0x%p): unexpected end of stream\n",
  302. PR_GetCurrentThread()));
  303. break;
  304. }
  305. filebytes += bytes;
  306. }
  307. rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
  308. if (Aborted(rv)) {
  309. goto aborted;
  310. }
  311. TEST_ASSERT(PR_SUCCESS == rv);
  312. retry:
  313. (void)PR_Close(fd); fd = NULL;
  314. TEST_LOG(
  315. cltsrv_log_file, TEST_LOG_INFO,
  316. ("\tClient(0x%p): disconnected from server\n", me));
  317. PR_Lock(client->ml);
  318. client->operations += 1;
  319. client->bytesTransferred += 2 * descbytes;
  320. rv = PR_WaitCondVar(client->stateChange, rand() % clipping);
  321. PR_Unlock(client->ml);
  322. if (Aborted(rv)) {
  323. break;
  324. }
  325. }
  326. aborted:
  327. client->stopped = PR_IntervalNow();
  328. PR_ClearInterrupt();
  329. if (NULL != fd) {
  330. rv = PR_Close(fd);
  331. }
  332. PR_Lock(client->ml);
  333. client->state = cs_exit;
  334. PR_NotifyCondVar(client->stateChange);
  335. PR_Unlock(client->ml);
  336. PR_DELETE(descriptor);
  337. TEST_LOG(
  338. cltsrv_log_file, TEST_LOG_ALWAYS,
  339. ("\tClient(0x%p): stopped after %u operations and %u bytes\n",
  340. PR_GetCurrentThread(), client->operations, client->bytesTransferred));
  341. } /* Client */
  342. static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server)
  343. {
  344. PRStatus drv, rv;
  345. char buffer[1024];
  346. PRFileDesc *file = NULL;
  347. PRThread * me = PR_GetCurrentThread();
  348. PRInt32 bytes, descbytes, netbytes, filebytes = 0;
  349. CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t);
  350. PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_SERVER_TIMEOUT);
  351. TEST_LOG(
  352. cltsrv_log_file, TEST_LOG_VERBOSE,
  353. ("\tProcessRequest(0x%p): receiving desciptor\n", me));
  354. bytes = PR_Recv(
  355. fd, descriptor, sizeof(*descriptor), RECV_FLAGS, timeout);
  356. if (-1 == bytes)
  357. {
  358. rv = PR_FAILURE;
  359. if (Aborted(rv)) {
  360. goto exit;
  361. }
  362. if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  363. {
  364. TEST_LOG(
  365. cltsrv_log_file, TEST_LOG_ERROR,
  366. ("\tProcessRequest(0x%p): receive timeout\n", me));
  367. }
  368. goto exit;
  369. }
  370. if (0 == bytes)
  371. {
  372. rv = PR_FAILURE;
  373. TEST_LOG(
  374. cltsrv_log_file, TEST_LOG_ERROR,
  375. ("\tProcessRequest(0x%p): unexpected end of file\n", me));
  376. goto exit;
  377. }
  378. descbytes = PR_ntohl(descriptor->size);
  379. TEST_ASSERT(sizeof(*descriptor) == bytes);
  380. TEST_LOG(
  381. cltsrv_log_file, TEST_LOG_VERBOSE,
  382. ("\t\tProcessRequest(0x%p): read descriptor {%d, %s}\n",
  383. me, descbytes, descriptor->filename));
  384. file = PR_Open(
  385. descriptor->filename, (PR_CREATE_FILE | PR_WRONLY), 0666);
  386. if (NULL == file)
  387. {
  388. rv = PR_FAILURE;
  389. if (Aborted(rv)) {
  390. goto aborted;
  391. }
  392. if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  393. {
  394. TEST_LOG(
  395. cltsrv_log_file, TEST_LOG_ERROR,
  396. ("\tProcessRequest(0x%p): open file timeout\n", me));
  397. goto aborted;
  398. }
  399. }
  400. TEST_ASSERT(NULL != file);
  401. filebytes = 0;
  402. while (filebytes < descbytes)
  403. {
  404. netbytes = sizeof(buffer);
  405. if ((descbytes - filebytes) < netbytes) {
  406. netbytes = descbytes - filebytes;
  407. }
  408. TEST_LOG(
  409. cltsrv_log_file, TEST_LOG_VERBOSE,
  410. ("\tProcessRequest(0x%p): receive %d bytes\n", me, netbytes));
  411. bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout);
  412. if (-1 == bytes)
  413. {
  414. rv = PR_FAILURE;
  415. if (Aborted(rv)) {
  416. goto aborted;
  417. }
  418. if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  419. {
  420. TEST_LOG(
  421. cltsrv_log_file, TEST_LOG_ERROR,
  422. ("\t\tProcessRequest(0x%p): receive data timeout\n", me));
  423. goto aborted;
  424. }
  425. /*
  426. * XXX: I got (PR_CONNECT_RESET_ERROR, ERROR_NETNAME_DELETED)
  427. * on NT here. This is equivalent to ECONNRESET on Unix.
  428. * -wtc
  429. */
  430. TEST_LOG(
  431. cltsrv_log_file, TEST_LOG_WARNING,
  432. ("\t\tProcessRequest(0x%p): unexpected error (%d, %d)\n",
  433. me, PR_GetError(), PR_GetOSError()));
  434. goto aborted;
  435. }
  436. if(0 == bytes)
  437. {
  438. TEST_LOG(
  439. cltsrv_log_file, TEST_LOG_WARNING,
  440. ("\t\tProcessRequest(0x%p): unexpected end of stream\n", me));
  441. rv = PR_FAILURE;
  442. goto aborted;
  443. }
  444. filebytes += bytes;
  445. netbytes = bytes;
  446. /* The byte count for PR_Write should be positive */
  447. MY_ASSERT(netbytes > 0);
  448. TEST_LOG(
  449. cltsrv_log_file, TEST_LOG_VERBOSE,
  450. ("\tProcessRequest(0x%p): write %d bytes to file\n", me, netbytes));
  451. bytes = PR_Write(file, buffer, netbytes);
  452. if (netbytes != bytes)
  453. {
  454. rv = PR_FAILURE;
  455. if (Aborted(rv)) {
  456. goto aborted;
  457. }
  458. if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  459. {
  460. TEST_LOG(
  461. cltsrv_log_file, TEST_LOG_ERROR,
  462. ("\t\tProcessRequest(0x%p): write file timeout\n", me));
  463. goto aborted;
  464. }
  465. }
  466. TEST_ASSERT(bytes > 0);
  467. }
  468. PR_Lock(server->ml);
  469. server->operations += 1;
  470. server->bytesTransferred += filebytes;
  471. PR_Unlock(server->ml);
  472. rv = PR_Close(file);
  473. if (Aborted(rv)) {
  474. goto aborted;
  475. }
  476. TEST_ASSERT(PR_SUCCESS == rv);
  477. file = NULL;
  478. TEST_LOG(
  479. cltsrv_log_file, TEST_LOG_VERBOSE,
  480. ("\t\tProcessRequest(0x%p): opening %s\n", me, descriptor->filename));
  481. file = PR_Open(descriptor->filename, PR_RDONLY, 0);
  482. if (NULL == file)
  483. {
  484. rv = PR_FAILURE;
  485. if (Aborted(rv)) {
  486. goto aborted;
  487. }
  488. if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  489. {
  490. TEST_LOG(
  491. cltsrv_log_file, TEST_LOG_ERROR,
  492. ("\t\tProcessRequest(0x%p): open file timeout\n",
  493. PR_GetCurrentThread()));
  494. goto aborted;
  495. }
  496. TEST_LOG(
  497. cltsrv_log_file, TEST_LOG_ERROR,
  498. ("\t\tProcessRequest(0x%p): other file open error (%u, %u)\n",
  499. me, PR_GetError(), PR_GetOSError()));
  500. goto aborted;
  501. }
  502. TEST_ASSERT(NULL != file);
  503. netbytes = 0;
  504. while (netbytes < descbytes)
  505. {
  506. filebytes = sizeof(buffer);
  507. if ((descbytes - netbytes) < filebytes) {
  508. filebytes = descbytes - netbytes;
  509. }
  510. TEST_LOG(
  511. cltsrv_log_file, TEST_LOG_VERBOSE,
  512. ("\tProcessRequest(0x%p): read %d bytes from file\n", me, filebytes));
  513. bytes = PR_Read(file, buffer, filebytes);
  514. if (filebytes != bytes)
  515. {
  516. rv = PR_FAILURE;
  517. if (Aborted(rv)) {
  518. goto aborted;
  519. }
  520. if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  521. TEST_LOG(
  522. cltsrv_log_file, TEST_LOG_ERROR,
  523. ("\t\tProcessRequest(0x%p): read file timeout\n", me));
  524. else
  525. TEST_LOG(
  526. cltsrv_log_file, TEST_LOG_ERROR,
  527. ("\t\tProcessRequest(0x%p): other file error (%d, %d)\n",
  528. me, PR_GetError(), PR_GetOSError()));
  529. goto aborted;
  530. }
  531. TEST_ASSERT(bytes > 0);
  532. netbytes += bytes;
  533. filebytes = bytes;
  534. TEST_LOG(
  535. cltsrv_log_file, TEST_LOG_VERBOSE,
  536. ("\t\tProcessRequest(0x%p): sending %d bytes\n", me, filebytes));
  537. bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout);
  538. if (filebytes != bytes)
  539. {
  540. rv = PR_FAILURE;
  541. if (Aborted(rv)) {
  542. goto aborted;
  543. }
  544. if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  545. {
  546. TEST_LOG(
  547. cltsrv_log_file, TEST_LOG_ERROR,
  548. ("\t\tProcessRequest(0x%p): send data timeout\n", me));
  549. goto aborted;
  550. }
  551. break;
  552. }
  553. TEST_ASSERT(bytes > 0);
  554. }
  555. PR_Lock(server->ml);
  556. server->bytesTransferred += filebytes;
  557. PR_Unlock(server->ml);
  558. rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
  559. if (Aborted(rv)) {
  560. goto aborted;
  561. }
  562. rv = PR_Close(file);
  563. if (Aborted(rv)) {
  564. goto aborted;
  565. }
  566. TEST_ASSERT(PR_SUCCESS == rv);
  567. file = NULL;
  568. aborted:
  569. PR_ClearInterrupt();
  570. if (NULL != file) {
  571. PR_Close(file);
  572. }
  573. drv = PR_Delete(descriptor->filename);
  574. TEST_ASSERT(PR_SUCCESS == drv);
  575. exit:
  576. TEST_LOG(
  577. cltsrv_log_file, TEST_LOG_VERBOSE,
  578. ("\t\tProcessRequest(0x%p): Finished\n", me));
  579. PR_DELETE(descriptor);
  580. #if defined(WIN95)
  581. PR_Sleep(PR_MillisecondsToInterval(200)); /* lth. see note [1] */
  582. #endif
  583. return rv;
  584. } /* ProcessRequest */
  585. static PRStatus CreateWorker(CSServer_t *server, CSPool_t *pool)
  586. {
  587. CSWorker_t *worker = PR_NEWZAP(CSWorker_t);
  588. worker->server = server;
  589. PR_INIT_CLIST(&worker->element);
  590. worker->thread = PR_CreateThread(
  591. PR_USER_THREAD, Worker, worker,
  592. DEFAULT_SERVER_PRIORITY, thread_scope,
  593. PR_UNJOINABLE_THREAD, 0);
  594. if (NULL == worker->thread)
  595. {
  596. PR_DELETE(worker);
  597. return PR_FAILURE;
  598. }
  599. TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS,
  600. ("\tCreateWorker(0x%p): create new worker (0x%p)\n",
  601. PR_GetCurrentThread(), worker->thread));
  602. return PR_SUCCESS;
  603. } /* CreateWorker */
  604. static void PR_CALLBACK Worker(void *arg)
  605. {
  606. PRStatus rv;
  607. PRNetAddr from;
  608. PRFileDesc *fd = NULL;
  609. PRThread *me = PR_GetCurrentThread();
  610. CSWorker_t *worker = (CSWorker_t*)arg;
  611. CSServer_t *server = worker->server;
  612. CSPool_t *pool = &server->pool;
  613. TEST_LOG(
  614. cltsrv_log_file, TEST_LOG_NOTICE,
  615. ("\t\tWorker(0x%p): started [%u]\n", me, pool->workers + 1));
  616. PR_Lock(server->ml);
  617. PR_APPEND_LINK(&worker->element, &server->list);
  618. pool->workers += 1; /* define our existance */
  619. while (cs_run == server->state)
  620. {
  621. while (pool->accepting >= server->workers.accepting)
  622. {
  623. TEST_LOG(
  624. cltsrv_log_file, TEST_LOG_VERBOSE,
  625. ("\t\tWorker(0x%p): waiting for accept slot[%d]\n",
  626. me, pool->accepting));
  627. rv = PR_WaitCondVar(pool->acceptComplete, PR_INTERVAL_NO_TIMEOUT);
  628. if (Aborted(rv) || (cs_run != server->state))
  629. {
  630. TEST_LOG(
  631. cltsrv_log_file, TEST_LOG_NOTICE,
  632. ("\tWorker(0x%p): has been %s\n",
  633. me, (Aborted(rv) ? "interrupted" : "stopped")));
  634. goto exit;
  635. }
  636. }
  637. pool->accepting += 1; /* how many are really in accept */
  638. PR_Unlock(server->ml);
  639. TEST_LOG(
  640. cltsrv_log_file, TEST_LOG_VERBOSE,
  641. ("\t\tWorker(0x%p): calling accept\n", me));
  642. fd = PR_Accept(server->listener, &from, PR_INTERVAL_NO_TIMEOUT);
  643. PR_Lock(server->ml);
  644. pool->accepting -= 1;
  645. PR_NotifyCondVar(pool->acceptComplete);
  646. if ((NULL == fd) && Aborted(PR_FAILURE))
  647. {
  648. if (NULL != server->listener)
  649. {
  650. PR_Close(server->listener);
  651. server->listener = NULL;
  652. }
  653. goto exit;
  654. }
  655. if (NULL != fd)
  656. {
  657. /*
  658. ** Create another worker of the total number of workers is
  659. ** less than the minimum specified or we have none left in
  660. ** accept() AND we're not over the maximum.
  661. ** This sort of presumes that the number allowed in accept
  662. ** is at least as many as the minimum. Otherwise we'll keep
  663. ** creating new threads and deleting them soon after.
  664. */
  665. PRBool another =
  666. ((pool->workers < server->workers.minimum) ||
  667. ((0 == pool->accepting)
  668. && (pool->workers < server->workers.maximum))) ?
  669. PR_TRUE : PR_FALSE;
  670. pool->active += 1;
  671. PR_Unlock(server->ml);
  672. if (another) {
  673. (void)CreateWorker(server, pool);
  674. }
  675. rv = ProcessRequest(fd, server);
  676. if (PR_SUCCESS != rv)
  677. TEST_LOG(
  678. cltsrv_log_file, TEST_LOG_ERROR,
  679. ("\t\tWorker(0x%p): server process ended abnormally\n", me));
  680. (void)PR_Close(fd); fd = NULL;
  681. PR_Lock(server->ml);
  682. pool->active -= 1;
  683. }
  684. }
  685. exit:
  686. PR_ClearInterrupt();
  687. PR_Unlock(server->ml);
  688. if (NULL != fd)
  689. {
  690. (void)PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
  691. (void)PR_Close(fd);
  692. }
  693. TEST_LOG(
  694. cltsrv_log_file, TEST_LOG_NOTICE,
  695. ("\t\tWorker(0x%p): exiting [%u]\n", PR_GetCurrentThread(), pool->workers));
  696. PR_Lock(server->ml);
  697. pool->workers -= 1; /* undefine our existance */
  698. PR_REMOVE_AND_INIT_LINK(&worker->element);
  699. PR_NotifyCondVar(pool->exiting);
  700. PR_Unlock(server->ml);
  701. PR_DELETE(worker); /* destruction of the "worker" object */
  702. } /* Worker */
  703. static void PR_CALLBACK Server(void *arg)
  704. {
  705. PRStatus rv;
  706. PRNetAddr serverAddress;
  707. PRThread *me = PR_GetCurrentThread();
  708. CSServer_t *server = (CSServer_t*)arg;
  709. PRSocketOptionData sockOpt;
  710. server->listener = PR_Socket(domain, SOCK_STREAM, protocol);
  711. sockOpt.option = PR_SockOpt_Reuseaddr;
  712. sockOpt.value.reuse_addr = PR_TRUE;
  713. rv = PR_SetSocketOption(server->listener, &sockOpt);
  714. TEST_ASSERT(PR_SUCCESS == rv);
  715. memset(&serverAddress, 0, sizeof(serverAddress));
  716. if (PR_AF_INET6 != domain) {
  717. TEST_LOG(cltsrv_log_file, TEST_LOG_ALWAYS,
  718. ("server binding to ip port %s\n", DEFAULT_PORT));
  719. rv = PR_InitializeNetAddr(PR_IpAddrAny, DEFAULT_PORT, &serverAddress);
  720. }
  721. else {
  722. TEST_LOG(cltsrv_log_file, TEST_LOG_ALWAYS,
  723. ("server binding to ipv6 port %s\n", DEFAULT_PORT));
  724. rv = PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, DEFAULT_PORT,
  725. &serverAddress);
  726. }
  727. rv = PR_Bind(server->listener, &serverAddress);
  728. TEST_ASSERT(PR_SUCCESS == rv);
  729. rv = PR_Listen(server->listener, server->backlog);
  730. TEST_ASSERT(PR_SUCCESS == rv);
  731. server->started = PR_IntervalNow();
  732. TimeOfDayMessage("Server started at", me);
  733. PR_Lock(server->ml);
  734. server->state = cs_run;
  735. PR_NotifyCondVar(server->stateChange);
  736. PR_Unlock(server->ml);
  737. /*
  738. ** Create the first worker (actually, a thread that accepts
  739. ** connections and then processes the work load as needed).
  740. ** From this point on, additional worker threads are created
  741. ** as they are needed by existing worker threads.
  742. */
  743. rv = CreateWorker(server, &server->pool);
  744. TEST_ASSERT(PR_SUCCESS == rv);
  745. /*
  746. ** From here on this thread is merely hanging around as the contact
  747. ** point for the main test driver. It's just waiting for the driver
  748. ** to declare the test complete.
  749. */
  750. TEST_LOG(
  751. cltsrv_log_file, TEST_LOG_VERBOSE,
  752. ("\tServer(0x%p): waiting for state change\n", me));
  753. PR_Lock(server->ml);
  754. while ((cs_run == server->state) && !Aborted(rv))
  755. {
  756. rv = PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
  757. }
  758. PR_Unlock(server->ml);
  759. PR_ClearInterrupt();
  760. TEST_LOG(
  761. cltsrv_log_file, TEST_LOG_INFO,
  762. ("\tServer(0x%p): shutting down workers\n", me));
  763. /*
  764. ** Get all the worker threads to exit. They know how to
  765. ** clean up after themselves, so this is just a matter of
  766. ** waiting for clorine in the pool to take effect. During
  767. ** this stage we're ignoring interrupts.
  768. */
  769. server->workers.minimum = server->workers.maximum = 0;
  770. PR_Lock(server->ml);
  771. while (!PR_CLIST_IS_EMPTY(&server->list))
  772. {
  773. PRCList *head = PR_LIST_HEAD(&server->list);
  774. CSWorker_t *worker = (CSWorker_t*)head;
  775. TEST_LOG(
  776. cltsrv_log_file, TEST_LOG_VERBOSE,
  777. ("\tServer(0x%p): interrupting worker(0x%p)\n", me, worker));
  778. rv = PR_Interrupt(worker->thread);
  779. TEST_ASSERT(PR_SUCCESS == rv);
  780. PR_REMOVE_AND_INIT_LINK(head);
  781. }
  782. while (server->pool.workers > 0)
  783. {
  784. TEST_LOG(
  785. cltsrv_log_file, TEST_LOG_NOTICE,
  786. ("\tServer(0x%p): waiting for %u workers to exit\n",
  787. me, server->pool.workers));
  788. (void)PR_WaitCondVar(server->pool.exiting, PR_INTERVAL_NO_TIMEOUT);
  789. }
  790. server->state = cs_exit;
  791. PR_NotifyCondVar(server->stateChange);
  792. PR_Unlock(server->ml);
  793. TEST_LOG(
  794. cltsrv_log_file, TEST_LOG_ALWAYS,
  795. ("\tServer(0x%p): stopped after %u operations and %u bytes\n",
  796. me, server->operations, server->bytesTransferred));
  797. if (NULL != server->listener) {
  798. PR_Close(server->listener);
  799. }
  800. server->stopped = PR_IntervalNow();
  801. } /* Server */
  802. static void WaitForCompletion(PRIntn execution)
  803. {
  804. while (execution > 0)
  805. {
  806. PRIntn dally = (execution > 30) ? 30 : execution;
  807. PR_Sleep(PR_SecondsToInterval(dally));
  808. if (pthread_stats) {
  809. PT_FPrintStats(debug_out, "\nPThread Statistics\n");
  810. }
  811. execution -= dally;
  812. }
  813. } /* WaitForCompletion */
  814. static void Help(void)
  815. {
  816. PR_fprintf(debug_out, "cltsrv test program usage:\n");
  817. PR_fprintf(debug_out, "\t-a <n> threads allowed in accept (5)\n");
  818. PR_fprintf(debug_out, "\t-b <n> backlock for listen (5)\n");
  819. PR_fprintf(debug_out, "\t-c <threads> number of clients to create (1)\n");
  820. PR_fprintf(debug_out, "\t-f <low> low water mark for fd caching (0)\n");
  821. PR_fprintf(debug_out, "\t-F <high> high water mark for fd caching (0)\n");
  822. PR_fprintf(debug_out, "\t-w <threads> minimal number of server threads (1)\n");
  823. PR_fprintf(debug_out, "\t-W <threads> maximum number of server threads (1)\n");
  824. PR_fprintf(debug_out, "\t-e <seconds> duration of the test in seconds (10)\n");
  825. PR_fprintf(debug_out, "\t-s <string> dsn name of server (localhost)\n");
  826. PR_fprintf(debug_out, "\t-G use GLOBAL threads (LOCAL)\n");
  827. PR_fprintf(debug_out, "\t-X use XTP as transport (TCP)\n");
  828. PR_fprintf(debug_out, "\t-6 Use IPv6 (IPv4)\n");
  829. PR_fprintf(debug_out, "\t-v verbosity (accumulative) (0)\n");
  830. PR_fprintf(debug_out, "\t-p pthread statistics (FALSE)\n");
  831. PR_fprintf(debug_out, "\t-d debug mode (FALSE)\n");
  832. PR_fprintf(debug_out, "\t-h this message\n");
  833. } /* Help */
  834. static Verbosity IncrementVerbosity(void)
  835. {
  836. PRIntn verboge = (PRIntn)verbosity + 1;
  837. return (Verbosity)verboge;
  838. } /* IncrementVerbosity */
  839. int main(int argc, char** argv)
  840. {
  841. PRUintn index;
  842. PRBool boolean;
  843. CSClient_t *client;
  844. PRStatus rv, joinStatus;
  845. CSServer_t *server = NULL;
  846. PRUintn backlog = DEFAULT_BACKLOG;
  847. PRUintn clients = DEFAULT_CLIENTS;
  848. const char *serverName = DEFAULT_SERVER;
  849. PRBool serverIsLocal = PR_TRUE;
  850. PRUintn accepting = ALLOWED_IN_ACCEPT;
  851. PRUintn workersMin = DEFAULT_WORKERS_MIN;
  852. PRUintn workersMax = DEFAULT_WORKERS_MAX;
  853. PRIntn execution = DEFAULT_EXECUTION_TIME;
  854. PRIntn low = DEFAULT_LOW, high = DEFAULT_HIGH;
  855. /*
  856. * -G use global threads
  857. * -a <n> threads allowed in accept
  858. * -b <n> backlock for listen
  859. * -c <threads> number of clients to create
  860. * -f <low> low water mark for caching FDs
  861. * -F <high> high water mark for caching FDs
  862. * -w <threads> minimal number of server threads
  863. * -W <threads> maximum number of server threads
  864. * -e <seconds> duration of the test in seconds
  865. * -s <string> dsn name of server (implies no server here)
  866. * -v verbosity
  867. */
  868. PLOptStatus os;
  869. PLOptState *opt = PL_CreateOptState(argc, argv, "GX6b:a:c:f:F:w:W:e:s:vdhp");
  870. debug_out = PR_GetSpecialFD(PR_StandardError);
  871. while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
  872. {
  873. if (PL_OPT_BAD == os) {
  874. continue;
  875. }
  876. switch (opt->option)
  877. {
  878. case 'G': /* use global threads */
  879. thread_scope = PR_GLOBAL_THREAD;
  880. break;
  881. case 'X': /* use XTP as transport */
  882. protocol = 36;
  883. break;
  884. case '6': /* Use IPv6 */
  885. domain = PR_AF_INET6;
  886. break;
  887. case 'a': /* the value for accepting */
  888. accepting = atoi(opt->value);
  889. break;
  890. case 'b': /* the value for backlock */
  891. backlog = atoi(opt->value);
  892. break;
  893. case 'c': /* number of client threads */
  894. clients = atoi(opt->value);
  895. break;
  896. case 'f': /* low water fd cache */
  897. low = atoi(opt->value);
  898. break;
  899. case 'F': /* low water fd cache */
  900. high = atoi(opt->value);
  901. break;
  902. case 'w': /* minimum server worker threads */
  903. workersMin = atoi(opt->value);
  904. break;
  905. case 'W': /* maximum server worker threads */
  906. workersMax = atoi(opt->value);
  907. break;
  908. case 'e': /* program execution time in seconds */
  909. execution = atoi(opt->value);
  910. break;
  911. case 's': /* server's address */
  912. serverName = opt->value;
  913. break;
  914. case 'v': /* verbosity */
  915. verbosity = IncrementVerbosity();
  916. break;
  917. case 'd': /* debug mode */
  918. debug_mode = PR_TRUE;
  919. break;
  920. case 'p': /* pthread mode */
  921. pthread_stats = PR_TRUE;
  922. break;
  923. case 'h':
  924. default:
  925. Help();
  926. return 2;
  927. }
  928. }
  929. PL_DestroyOptState(opt);
  930. if (0 != PL_strcmp(serverName, DEFAULT_SERVER)) {
  931. serverIsLocal = PR_FALSE;
  932. }
  933. if (0 == execution) {
  934. execution = DEFAULT_EXECUTION_TIME;
  935. }
  936. if (0 == workersMax) {
  937. workersMax = DEFAULT_WORKERS_MAX;
  938. }
  939. if (0 == workersMin) {
  940. workersMin = DEFAULT_WORKERS_MIN;
  941. }
  942. if (0 == accepting) {
  943. accepting = ALLOWED_IN_ACCEPT;
  944. }
  945. if (0 == backlog) {
  946. backlog = DEFAULT_BACKLOG;
  947. }
  948. if (workersMin > accepting) {
  949. accepting = workersMin;
  950. }
  951. PR_STDIO_INIT();
  952. TimeOfDayMessage("Client/Server started at", PR_GetCurrentThread());
  953. cltsrv_log_file = PR_NewLogModule("cltsrv_log");
  954. MY_ASSERT(NULL != cltsrv_log_file);
  955. boolean = PR_SetLogFile("cltsrv.log");
  956. MY_ASSERT(boolean);
  957. rv = PR_SetFDCacheSize(low, high);
  958. PR_ASSERT(PR_SUCCESS == rv);
  959. if (serverIsLocal)
  960. {
  961. /* Establish the server */
  962. TEST_LOG(
  963. cltsrv_log_file, TEST_LOG_INFO,
  964. ("main(0x%p): starting server\n", PR_GetCurrentThread()));
  965. server = PR_NEWZAP(CSServer_t);
  966. PR_INIT_CLIST(&server->list);
  967. server->state = cs_init;
  968. server->ml = PR_NewLock();
  969. server->backlog = backlog;
  970. server->port = DEFAULT_PORT;
  971. server->workers.minimum = workersMin;
  972. server->workers.maximum = workersMax;
  973. server->workers.accepting = accepting;
  974. server->stateChange = PR_NewCondVar(server->ml);
  975. server->pool.exiting = PR_NewCondVar(server->ml);
  976. server->pool.acceptComplete = PR_NewCondVar(server->ml);
  977. TEST_LOG(
  978. cltsrv_log_file, TEST_LOG_NOTICE,
  979. ("main(0x%p): creating server thread\n", PR_GetCurrentThread()));
  980. server->thread = PR_CreateThread(
  981. PR_USER_THREAD, Server, server, PR_PRIORITY_HIGH,
  982. thread_scope, PR_JOINABLE_THREAD, 0);
  983. TEST_ASSERT(NULL != server->thread);
  984. TEST_LOG(
  985. cltsrv_log_file, TEST_LOG_VERBOSE,
  986. ("main(0x%p): waiting for server init\n", PR_GetCurrentThread()));
  987. PR_Lock(server->ml);
  988. while (server->state == cs_init) {
  989. PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
  990. }
  991. PR_Unlock(server->ml);
  992. TEST_LOG(
  993. cltsrv_log_file, TEST_LOG_VERBOSE,
  994. ("main(0x%p): server init complete (port #%d)\n",
  995. PR_GetCurrentThread(), server->port));
  996. }
  997. if (clients != 0)
  998. {
  999. /* Create all of the clients */
  1000. PRHostEnt host;
  1001. char buffer[BUFFER_SIZE];
  1002. client = (CSClient_t*)PR_CALLOC(clients * sizeof(CSClient_t));
  1003. TEST_LOG(
  1004. cltsrv_log_file, TEST_LOG_VERBOSE,
  1005. ("main(0x%p): creating %d client threads\n",
  1006. PR_GetCurrentThread(), clients));
  1007. if (!serverIsLocal)
  1008. {
  1009. rv = PR_GetHostByName(serverName, buffer, BUFFER_SIZE, &host);
  1010. if (PR_SUCCESS != rv)
  1011. {
  1012. PL_FPrintError(PR_STDERR, "PR_GetHostByName");
  1013. return 2;
  1014. }
  1015. }
  1016. for (index = 0; index < clients; ++index)
  1017. {
  1018. client[index].state = cs_init;
  1019. client[index].ml = PR_NewLock();
  1020. if (serverIsLocal)
  1021. {
  1022. if (PR_AF_INET6 != domain) {
  1023. TEST_LOG(cltsrv_log_file, TEST_LOG_ALWAYS,
  1024. ("loopback client ip port %s\n", DEFAULT_PORT));
  1025. (void)PR_InitializeNetAddr(
  1026. PR_IpAddrLoopback, DEFAULT_PORT,
  1027. &client[index].serverAddress);
  1028. }
  1029. else {
  1030. TEST_LOG(cltsrv_log_file, TEST_LOG_ALWAYS,
  1031. ("loopback client ipv6 port %s\n", DEFAULT_PORT));
  1032. rv = PR_SetNetAddr(PR_IpAddrLoopback, PR_AF_INET6,
  1033. DEFAULT_PORT, &client[index].serverAddress);
  1034. }
  1035. }
  1036. else
  1037. {
  1038. TEST_LOG(cltsrv_log_file, TEST_LOG_ALWAYS,
  1039. ("client enumerate port %s\n", DEFAULT_PORT));
  1040. (void)PR_EnumerateHostEnt(
  1041. 0, &host, DEFAULT_PORT, &client[index].serverAddress);
  1042. }
  1043. client[index].stateChange = PR_NewCondVar(client[index].ml);
  1044. TEST_LOG(
  1045. cltsrv_log_file, TEST_LOG_INFO,
  1046. ("main(0x%p): creating client threads\n", PR_GetCurrentThread()));
  1047. client[index].thread = PR_CreateThread(
  1048. PR_USER_THREAD, Client, &client[index], PR_PRIORITY_NORMAL,
  1049. thread_scope, PR_JOINABLE_THREAD, 0);
  1050. TEST_ASSERT(NULL != client[index].thread);
  1051. PR_Lock(client[index].ml);
  1052. while (cs_init == client[index].state) {
  1053. PR_WaitCondVar(client[index].stateChange, PR_INTERVAL_NO_TIMEOUT);
  1054. }
  1055. PR_Unlock(client[index].ml);
  1056. }
  1057. }
  1058. /* Then just let them go at it for a bit */
  1059. TEST_LOG(
  1060. cltsrv_log_file, TEST_LOG_ALWAYS,
  1061. ("main(0x%p): waiting for execution interval (%d seconds)\n",
  1062. PR_GetCurrentThread(), execution));
  1063. WaitForCompletion(execution);
  1064. TimeOfDayMessage("Shutting down", PR_GetCurrentThread());
  1065. if (clients != 0)
  1066. {
  1067. for (index = 0; index < clients; ++index)
  1068. {
  1069. TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS,
  1070. ("main(0x%p): notifying client(0x%p) to stop\n",
  1071. PR_GetCurrentThread(), client[index].thread));
  1072. PR_Lock(client[index].ml);
  1073. if (cs_run == client[index].state)
  1074. {
  1075. client[index].state = cs_stop;
  1076. PR_Interrupt(client[index].thread);
  1077. while (cs_stop == client[index].state)
  1078. PR_WaitCondVar(
  1079. client[index].stateChange, PR_INTERVAL_NO_TIMEOUT);
  1080. }
  1081. PR_Unlock(client[index].ml);
  1082. TEST_LOG(cltsrv_log_file, TEST_LOG_VERBOSE,
  1083. ("main(0x%p): joining client(0x%p)\n",
  1084. PR_GetCurrentThread(), client[index].thread));
  1085. joinStatus = PR_JoinThread(client[index].thread);
  1086. TEST_ASSERT(PR_SUCCESS == joinStatus);
  1087. PR_DestroyCondVar(client[index].stateChange);
  1088. PR_DestroyLock(client[index].ml);
  1089. }
  1090. PR_DELETE(client);
  1091. }
  1092. if (NULL != server)
  1093. {
  1094. /* All clients joined - retrieve the server */
  1095. TEST_LOG(
  1096. cltsrv_log_file, TEST_LOG_NOTICE,
  1097. ("main(0x%p): notifying server(0x%p) to stop\n",
  1098. PR_GetCurrentThread(), server->thread));
  1099. PR_Lock(server->ml);
  1100. server->state = cs_stop;
  1101. PR_Interrupt(server->thread);
  1102. while (cs_exit != server->state) {
  1103. PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
  1104. }
  1105. PR_Unlock(server->ml);
  1106. TEST_LOG(
  1107. cltsrv_log_file, TEST_LOG_NOTICE,
  1108. ("main(0x%p): joining server(0x%p)\n",
  1109. PR_GetCurrentThread(), server->thread));
  1110. joinStatus = PR_JoinThread(server->thread);
  1111. TEST_ASSERT(PR_SUCCESS == joinStatus);
  1112. PR_DestroyCondVar(server->stateChange);
  1113. PR_DestroyCondVar(server->pool.exiting);
  1114. PR_DestroyCondVar(server->pool.acceptComplete);
  1115. PR_DestroyLock(server->ml);
  1116. PR_DELETE(server);
  1117. }
  1118. TEST_LOG(
  1119. cltsrv_log_file, TEST_LOG_ALWAYS,
  1120. ("main(0x%p): test complete\n", PR_GetCurrentThread()));
  1121. PT_FPrintStats(debug_out, "\nPThread Statistics\n");
  1122. TimeOfDayMessage("Test exiting at", PR_GetCurrentThread());
  1123. PR_Cleanup();
  1124. return 0;
  1125. } /* main */
  1126. /* cltsrv.c */