VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/nsprpub/pr/tests/provider.c@ 26515

Last change on this file since 26515 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 45.8 KB
Line 
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 *
15 * The Original Code is the Netscape Portable Runtime (NSPR).
16 *
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998-2000
20 * the Initial Developer. All Rights Reserved.
21 *
22 * Contributor(s):
23 *
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
35 *
36 * ***** END LICENSE BLOCK ***** */
37
38/*
39 *
40 * Notes:
41 * [1] lth. The call to Sleep() is a hack to get the test case to run
42 * on Windows 95. Without it, the test case fails with an error
43 * WSAECONNRESET following a recv() call. The error is caused by the
44 * server side thread termination without a shutdown() or closesocket()
45 * call. Windows docmunentation suggests that this is predicted
46 * behavior; that other platforms get away with it is ... serindipity.
47 * The test case should shutdown() or closesocket() before
48 * thread termination. I didn't have time to figure out where or how
49 * to do it. The Sleep() call inserts enough delay to allow the
50 * client side to recv() all his data before the server side thread
51 * terminates. Whew! ...
52 *
53 ** Modification History:
54 * 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
55 * The debug mode will print all of the printfs associated with this test.
56 * The regress mode will be the default mode. Since the regress tool limits
57 * the output to a one line status:PASS or FAIL,all of the printf statements
58 * have been handled with an if (debug_mode) statement.
59 */
60
61#include "prclist.h"
62#include "prcvar.h"
63#include "prerror.h"
64#include "prinit.h"
65#include "prinrval.h"
66#include "prio.h"
67#include "prlock.h"
68#include "prlog.h"
69#include "prtime.h"
70#include "prmem.h"
71#include "prnetdb.h"
72#include "prprf.h"
73#include "prthread.h"
74
75#include "pprio.h"
76#include "primpl.h"
77
78#include "plstr.h"
79#include "plerror.h"
80#include "plgetopt.h"
81
82#include <stdlib.h>
83#include <string.h>
84
85
86#if defined(XP_UNIX)
87#include <math.h>
88#endif
89
90#ifdef XP_MAC
91#include "prlog.h"
92#define printf PR_LogPrint
93#endif
94
95/*
96** This is the beginning of the test
97*/
98
99#define RECV_FLAGS 0
100#define SEND_FLAGS 0
101#define BUFFER_SIZE 1024
102#define DEFAULT_BACKLOG 5
103#define DEFAULT_PORT 13000
104#define DEFAULT_CLIENTS 1
105#define ALLOWED_IN_ACCEPT 1
106#define DEFAULT_CLIPPING 1000
107#define DEFAULT_WORKERS_MIN 1
108#define DEFAULT_WORKERS_MAX 1
109#define DEFAULT_SERVER "localhost"
110#define DEFAULT_EXECUTION_TIME 10
111#define DEFAULT_CLIENT_TIMEOUT 4000
112#define DEFAULT_SERVER_TIMEOUT 4000
113#define DEFAULT_SERVER_PRIORITY PR_PRIORITY_HIGH
114
115typedef enum CSState_e {cs_init, cs_run, cs_stop, cs_exit} CSState_t;
116
117static void PR_CALLBACK Worker(void *arg);
118typedef struct CSPool_s CSPool_t;
119typedef struct CSWorker_s CSWorker_t;
120typedef struct CSServer_s CSServer_t;
121typedef enum Verbosity
122{
123 TEST_LOG_ALWAYS,
124 TEST_LOG_ERROR,
125 TEST_LOG_WARNING,
126 TEST_LOG_NOTICE,
127 TEST_LOG_INFO,
128 TEST_LOG_STATUS,
129 TEST_LOG_VERBOSE
130} Verbosity;
131
132static enum {
133 thread_nspr, thread_pthread, thread_uithread, thread_sproc, thread_win32
134} thread_provider;
135
136static PRInt32 domain = AF_INET;
137static PRInt32 protocol = 6; /* TCP */
138static PRFileDesc *debug_out = NULL;
139static PRBool debug_mode = PR_FALSE;
140static PRBool pthread_stats = PR_FALSE;
141static Verbosity verbosity = TEST_LOG_ALWAYS;
142static PRThreadScope thread_scope = PR_LOCAL_THREAD;
143
144struct CSWorker_s
145{
146 PRCList element; /* list of the server's workers */
147
148 PRThread *thread; /* this worker objects thread */
149 CSServer_t *server; /* back pointer to server structure */
150};
151
152struct CSPool_s
153{
154 PRCondVar *exiting;
155 PRCondVar *acceptComplete;
156 PRUint32 accepting, active, workers;
157};
158
159struct CSServer_s
160{
161 PRCList list; /* head of worker list */
162
163 PRLock *ml;
164 PRThread *thread; /* the main server thread */
165 PRCondVar *stateChange;
166
167 PRUint16 port; /* port we're listening on */
168 PRUint32 backlog; /* size of our listener backlog */
169 PRFileDesc *listener; /* the fd accepting connections */
170
171 CSPool_t pool; /* statistics on worker threads */
172 CSState_t state; /* the server's state */
173 struct /* controlling worker counts */
174 {
175 PRUint32 minimum, maximum, accepting;
176 } workers;
177
178 /* statistics */
179 PRIntervalTime started, stopped;
180 PRUint32 operations, bytesTransferred;
181};
182
183typedef struct CSDescriptor_s
184{
185 PRInt32 size; /* size of transfer */
186 char filename[60]; /* filename, null padded */
187} CSDescriptor_t;
188
189typedef struct CSClient_s
190{
191 PRLock *ml;
192 PRThread *thread;
193 PRCondVar *stateChange;
194 PRNetAddr serverAddress;
195
196 CSState_t state;
197
198 /* statistics */
199 PRIntervalTime started, stopped;
200 PRUint32 operations, bytesTransferred;
201} CSClient_t;
202
203#define TEST_LOG(l, p, a) \
204 do { \
205 if (debug_mode || (p <= verbosity)) printf a; \
206 } while (0)
207
208PRLogModuleInfo *cltsrv_log_file = NULL;
209
210#define MY_ASSERT(_expr) \
211 ((_expr)?((void)0):_MY_Assert(# _expr,__FILE__,__LINE__))
212
213#define TEST_ASSERT(_expr) \
214 ((_expr)?((void)0):_MY_Assert(# _expr,__FILE__,__LINE__))
215
216static void _MY_Assert(const char *s, const char *file, PRIntn ln)
217{
218 PL_PrintError(NULL);
219#if DEBUG
220 PR_Assert(s, file, ln);
221#endif
222} /* _MW_Assert */
223
224static PRBool Aborted(PRStatus rv)
225{
226 return ((PR_FAILURE == rv) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) ?
227 PR_TRUE : PR_FALSE;
228}
229
230static void TimeOfDayMessage(const char *msg, PRThread* me)
231{
232 char buffer[100];
233 PRExplodedTime tod;
234 PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &tod);
235 (void)PR_FormatTime(buffer, sizeof(buffer), "%T", &tod);
236
237 TEST_LOG(
238 cltsrv_log_file, TEST_LOG_ALWAYS,
239 ("%s(0x%p): %s\n", msg, me, buffer));
240} /* TimeOfDayMessage */
241
242
243static void PR_CALLBACK Client(void *arg)
244{
245 PRStatus rv;
246 PRIntn index;
247 char buffer[1024];
248 PRFileDesc *fd = NULL;
249 PRUintn clipping = DEFAULT_CLIPPING;
250 CSClient_t *client = (CSClient_t*)arg;
251 PRThread *me = client->thread = PR_CurrentThread();
252 CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t);
253 PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_CLIENT_TIMEOUT);
254
255
256 for (index = 0; index < sizeof(buffer); ++index)
257 buffer[index] = (char)index;
258
259 client->started = PR_IntervalNow();
260
261 PR_Lock(client->ml);
262 client->state = cs_run;
263 PR_NotifyCondVar(client->stateChange);
264 PR_Unlock(client->ml);
265
266 TimeOfDayMessage("Client started at", me);
267
268 while (cs_run == client->state)
269 {
270 PRInt32 bytes, descbytes, filebytes, netbytes;
271
272 (void)PR_NetAddrToString(&client->serverAddress, buffer, sizeof(buffer));
273 TEST_LOG(cltsrv_log_file, TEST_LOG_INFO,
274 ("\tClient(0x%p): connecting to server at %s\n", me, buffer));
275
276 fd = PR_Socket(domain, SOCK_STREAM, protocol);
277 TEST_ASSERT(NULL != fd);
278 rv = PR_Connect(fd, &client->serverAddress, timeout);
279 if (PR_FAILURE == rv)
280 {
281 TEST_LOG(
282 cltsrv_log_file, TEST_LOG_ERROR,
283 ("\tClient(0x%p): conection failed\n", me));
284 goto aborted;
285 }
286
287 memset(descriptor, 0, sizeof(*descriptor));
288 descriptor->size = PR_htonl(descbytes = rand() % clipping);
289 PR_snprintf(
290 descriptor->filename, sizeof(descriptor->filename),
291 "CS%p%p-%p.dat", client->started, me, client->operations);
292 TEST_LOG(
293 cltsrv_log_file, TEST_LOG_VERBOSE,
294 ("\tClient(0x%p): sending descriptor for %u bytes\n", me, descbytes));
295 bytes = PR_Send(
296 fd, descriptor, sizeof(*descriptor), SEND_FLAGS, timeout);
297 if (sizeof(CSDescriptor_t) != bytes)
298 {
299 if (Aborted(PR_FAILURE)) goto aborted;
300 if (PR_IO_TIMEOUT_ERROR == PR_GetError())
301 {
302 TEST_LOG(
303 cltsrv_log_file, TEST_LOG_ERROR,
304 ("\tClient(0x%p): send descriptor timeout\n", me));
305 goto retry;
306 }
307 }
308 TEST_ASSERT(sizeof(*descriptor) == bytes);
309
310 netbytes = 0;
311 while (netbytes < descbytes)
312 {
313 filebytes = sizeof(buffer);
314 if ((descbytes - netbytes) < filebytes)
315 filebytes = descbytes - netbytes;
316 TEST_LOG(
317 cltsrv_log_file, TEST_LOG_VERBOSE,
318 ("\tClient(0x%p): sending %d bytes\n", me, filebytes));
319 bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout);
320 if (filebytes != bytes)
321 {
322 if (Aborted(PR_FAILURE)) goto aborted;
323 if (PR_IO_TIMEOUT_ERROR == PR_GetError())
324 {
325 TEST_LOG(
326 cltsrv_log_file, TEST_LOG_ERROR,
327 ("\tClient(0x%p): send data timeout\n", me));
328 goto retry;
329 }
330 }
331 TEST_ASSERT(bytes == filebytes);
332 netbytes += bytes;
333 }
334 filebytes = 0;
335 while (filebytes < descbytes)
336 {
337 netbytes = sizeof(buffer);
338 if ((descbytes - filebytes) < netbytes)
339 netbytes = descbytes - filebytes;
340 TEST_LOG(
341 cltsrv_log_file, TEST_LOG_VERBOSE,
342 ("\tClient(0x%p): receiving %d bytes\n", me, netbytes));
343 bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout);
344 if (-1 == bytes)
345 {
346 if (Aborted(PR_FAILURE))
347 {
348 TEST_LOG(
349 cltsrv_log_file, TEST_LOG_ERROR,
350 ("\tClient(0x%p): receive data aborted\n", me));
351 goto aborted;
352 }
353 else if (PR_IO_TIMEOUT_ERROR == PR_GetError())
354 TEST_LOG(
355 cltsrv_log_file, TEST_LOG_ERROR,
356 ("\tClient(0x%p): receive data timeout\n", me));
357 else
358 TEST_LOG(
359 cltsrv_log_file, TEST_LOG_ERROR,
360 ("\tClient(0x%p): receive error (%d, %d)\n",
361 me, PR_GetError(), PR_GetOSError()));
362 goto retry;
363 }
364 if (0 == bytes)
365 {
366 TEST_LOG(
367 cltsrv_log_file, TEST_LOG_ERROR,
368 ("\t\tClient(0x%p): unexpected end of stream\n",
369 PR_CurrentThread()));
370 break;
371 }
372 filebytes += bytes;
373 }
374
375 rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
376 if (Aborted(rv)) goto aborted;
377 TEST_ASSERT(PR_SUCCESS == rv);
378retry:
379 (void)PR_Close(fd); fd = NULL;
380 TEST_LOG(
381 cltsrv_log_file, TEST_LOG_INFO,
382 ("\tClient(0x%p): disconnected from server\n", me));
383
384 PR_Lock(client->ml);
385 client->operations += 1;
386 client->bytesTransferred += 2 * descbytes;
387 rv = PR_WaitCondVar(client->stateChange, rand() % clipping);
388 PR_Unlock(client->ml);
389 if (Aborted(rv)) break;
390 }
391
392aborted:
393 client->stopped = PR_IntervalNow();
394
395 PR_ClearInterrupt();
396 if (NULL != fd) rv = PR_Close(fd);
397
398 PR_Lock(client->ml);
399 client->state = cs_exit;
400 PR_NotifyCondVar(client->stateChange);
401 PR_Unlock(client->ml);
402 PR_DELETE(descriptor);
403 TEST_LOG(
404 cltsrv_log_file, TEST_LOG_ALWAYS,
405 ("\tClient(0x%p): stopped after %u operations and %u bytes\n",
406 PR_CurrentThread(), client->operations, client->bytesTransferred));
407
408} /* Client */
409
410static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server)
411{
412 PRStatus drv, rv;
413 char buffer[1024];
414 PRFileDesc *file = NULL;
415 PRThread * me = PR_CurrentThread();
416 PRInt32 bytes, descbytes, netbytes, filebytes = 0;
417 CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t);
418 PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_SERVER_TIMEOUT);
419
420 TEST_LOG(
421 cltsrv_log_file, TEST_LOG_VERBOSE,
422 ("\tProcessRequest(0x%p): receiving desciptor\n", me));
423 bytes = PR_Recv(
424 fd, descriptor, sizeof(*descriptor), RECV_FLAGS, timeout);
425 if (-1 == bytes)
426 {
427 rv = PR_FAILURE;
428 if (Aborted(rv)) goto exit;
429 if (PR_IO_TIMEOUT_ERROR == PR_GetError())
430 {
431 TEST_LOG(
432 cltsrv_log_file, TEST_LOG_ERROR,
433 ("\tProcessRequest(0x%p): receive timeout\n", me));
434 }
435 goto exit;
436 }
437 if (0 == bytes)
438 {
439 rv = PR_FAILURE;
440 TEST_LOG(
441 cltsrv_log_file, TEST_LOG_ERROR,
442 ("\tProcessRequest(0x%p): unexpected end of file\n", me));
443 goto exit;
444 }
445 descbytes = PR_ntohl(descriptor->size);
446 TEST_ASSERT(sizeof(*descriptor) == bytes);
447
448 TEST_LOG(
449 cltsrv_log_file, TEST_LOG_VERBOSE,
450 ("\t\tProcessRequest(0x%p): read descriptor {%d, %s}\n",
451 me, descbytes, descriptor->filename));
452
453 file = PR_Open(
454 descriptor->filename, (PR_CREATE_FILE | PR_WRONLY), 0666);
455 if (NULL == file)
456 {
457 rv = PR_FAILURE;
458 if (Aborted(rv)) goto aborted;
459 if (PR_IO_TIMEOUT_ERROR == PR_GetError())
460 {
461 TEST_LOG(
462 cltsrv_log_file, TEST_LOG_ERROR,
463 ("\tProcessRequest(0x%p): open file timeout\n", me));
464 goto aborted;
465 }
466 }
467 TEST_ASSERT(NULL != file);
468
469 filebytes = 0;
470 while (filebytes < descbytes)
471 {
472 netbytes = sizeof(buffer);
473 if ((descbytes - filebytes) < netbytes)
474 netbytes = descbytes - filebytes;
475 TEST_LOG(
476 cltsrv_log_file, TEST_LOG_VERBOSE,
477 ("\tProcessRequest(0x%p): receive %d bytes\n", me, netbytes));
478 bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout);
479 if (-1 == bytes)
480 {
481 rv = PR_FAILURE;
482 if (Aborted(rv)) goto aborted;
483 if (PR_IO_TIMEOUT_ERROR == PR_GetError())
484 {
485 TEST_LOG(
486 cltsrv_log_file, TEST_LOG_ERROR,
487 ("\t\tProcessRequest(0x%p): receive data timeout\n", me));
488 goto aborted;
489 }
490 /*
491 * XXX: I got (PR_CONNECT_RESET_ERROR, ERROR_NETNAME_DELETED)
492 * on NT here. This is equivalent to ECONNRESET on Unix.
493 * -wtc
494 */
495 TEST_LOG(
496 cltsrv_log_file, TEST_LOG_WARNING,
497 ("\t\tProcessRequest(0x%p): unexpected error (%d, %d)\n",
498 me, PR_GetError(), PR_GetOSError()));
499 goto aborted;
500 }
501 if(0 == bytes)
502 {
503 TEST_LOG(
504 cltsrv_log_file, TEST_LOG_WARNING,
505 ("\t\tProcessRequest(0x%p): unexpected end of stream\n", me));
506 rv = PR_FAILURE;
507 goto aborted;
508 }
509 filebytes += bytes;
510 netbytes = bytes;
511 /* The byte count for PR_Write should be positive */
512 MY_ASSERT(netbytes > 0);
513 TEST_LOG(
514 cltsrv_log_file, TEST_LOG_VERBOSE,
515 ("\tProcessRequest(0x%p): write %d bytes to file\n", me, netbytes));
516 bytes = PR_Write(file, buffer, netbytes);
517 if (netbytes != bytes)
518 {
519 rv = PR_FAILURE;
520 if (Aborted(rv)) goto aborted;
521 if (PR_IO_TIMEOUT_ERROR == PR_GetError())
522 {
523 TEST_LOG(
524 cltsrv_log_file, TEST_LOG_ERROR,
525 ("\t\tProcessRequest(0x%p): write file timeout\n", me));
526 goto aborted;
527 }
528 }
529 TEST_ASSERT(bytes > 0);
530 }
531
532 PR_Lock(server->ml);
533 server->operations += 1;
534 server->bytesTransferred += filebytes;
535 PR_Unlock(server->ml);
536
537 rv = PR_Close(file); file = NULL;
538 if (Aborted(rv)) goto aborted;
539 TEST_ASSERT(PR_SUCCESS == rv);
540
541 TEST_LOG(
542 cltsrv_log_file, TEST_LOG_VERBOSE,
543 ("\t\tProcessRequest(0x%p): opening %s\n", me, descriptor->filename));
544 file = PR_Open(descriptor->filename, PR_RDONLY, 0);
545 if (NULL == file)
546 {
547 rv = PR_FAILURE;
548 if (Aborted(rv)) goto aborted;
549 if (PR_IO_TIMEOUT_ERROR == PR_GetError())
550 {
551 TEST_LOG(
552 cltsrv_log_file, TEST_LOG_ERROR,
553 ("\t\tProcessRequest(0x%p): open file timeout\n",
554 PR_CurrentThread()));
555 goto aborted;
556 }
557 TEST_LOG(
558 cltsrv_log_file, TEST_LOG_ERROR,
559 ("\t\tProcessRequest(0x%p): other file open error (%u, %u)\n",
560 me, PR_GetError(), PR_GetOSError()));
561 goto aborted;
562 }
563 TEST_ASSERT(NULL != file);
564
565 netbytes = 0;
566 while (netbytes < descbytes)
567 {
568 filebytes = sizeof(buffer);
569 if ((descbytes - netbytes) < filebytes)
570 filebytes = descbytes - netbytes;
571 TEST_LOG(
572 cltsrv_log_file, TEST_LOG_VERBOSE,
573 ("\tProcessRequest(0x%p): read %d bytes from file\n", me, filebytes));
574 bytes = PR_Read(file, buffer, filebytes);
575 if (filebytes != bytes)
576 {
577 rv = PR_FAILURE;
578 if (Aborted(rv)) goto aborted;
579 if (PR_IO_TIMEOUT_ERROR == PR_GetError())
580 TEST_LOG(
581 cltsrv_log_file, TEST_LOG_ERROR,
582 ("\t\tProcessRequest(0x%p): read file timeout\n", me));
583 else
584 TEST_LOG(
585 cltsrv_log_file, TEST_LOG_ERROR,
586 ("\t\tProcessRequest(0x%p): other file error (%d, %d)\n",
587 me, PR_GetError(), PR_GetOSError()));
588 goto aborted;
589 }
590 TEST_ASSERT(bytes > 0);
591 netbytes += bytes;
592 filebytes = bytes;
593 TEST_LOG(
594 cltsrv_log_file, TEST_LOG_VERBOSE,
595 ("\t\tProcessRequest(0x%p): sending %d bytes\n", me, filebytes));
596 bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout);
597 if (filebytes != bytes)
598 {
599 rv = PR_FAILURE;
600 if (Aborted(rv)) goto aborted;
601 if (PR_IO_TIMEOUT_ERROR == PR_GetError())
602 {
603 TEST_LOG(
604 cltsrv_log_file, TEST_LOG_ERROR,
605 ("\t\tProcessRequest(0x%p): send data timeout\n", me));
606 goto aborted;
607 }
608 break;
609 }
610 TEST_ASSERT(bytes > 0);
611 }
612
613 PR_Lock(server->ml);
614 server->bytesTransferred += filebytes;
615 PR_Unlock(server->ml);
616
617 rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
618 if (Aborted(rv)) goto aborted;
619
620 rv = PR_Close(file); file = NULL;
621 if (Aborted(rv)) goto aborted;
622 TEST_ASSERT(PR_SUCCESS == rv);
623
624aborted:
625 PR_ClearInterrupt();
626 if (NULL != file) PR_Close(file);
627 drv = PR_Delete(descriptor->filename);
628 TEST_ASSERT(PR_SUCCESS == drv);
629exit:
630 TEST_LOG(
631 cltsrv_log_file, TEST_LOG_VERBOSE,
632 ("\t\tProcessRequest(0x%p): Finished\n", me));
633
634 PR_DELETE(descriptor);
635
636#if defined(WIN95)
637 PR_Sleep(PR_MillisecondsToInterval(200)); /* lth. see note [1] */
638#endif
639 return rv;
640} /* ProcessRequest */
641
642typedef void (*StartFn)(void*);
643typedef struct StartObject
644{
645 StartFn start;
646 void *arg;
647} StartObject;
648
649#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
650#include "md/_pth.h"
651#include <pthread.h>
652
653static void *pthread_start(void *arg)
654{
655 StartObject *so = (StartObject*)arg;
656 StartFn start = so->start;
657 void *data = so->arg;
658 PR_Free(so);
659 start(data);
660 return NULL;
661} /* pthread_start */
662#endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */
663
664#if defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY)
665#include <thread.h>
666
667static void *uithread_start(void *arg)
668{
669 StartObject *so = (StartObject*)arg;
670 StartFn start = so->start;
671 void *data = so->arg;
672 PR_Free(so);
673 start(data);
674 return NULL;
675} /* uithread_start */
676#endif /* defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) */
677
678#if defined(IRIX) && !defined(_PR_PTHREADS)
679#include <sys/types.h>
680#include <sys/prctl.h>
681static void sproc_start(void *arg, PRSize size)
682{
683 StartObject *so = (StartObject*)arg;
684 StartFn start = so->start;
685 void *data = so->arg;
686 PR_Free(so);
687 start(data);
688} /* sproc_start */
689#endif /* defined(IRIX) && !defined(_PR_PTHREADS) */
690
691#if defined(WIN32)
692#include <process.h> /* for _beginthreadex() */
693
694static PRUintn __stdcall windows_start(void *arg)
695{
696 StartObject *so = (StartObject*)arg;
697 StartFn start = so->start;
698 void *data = so->arg;
699 PR_Free(so);
700 start(data);
701 return 0;
702} /* windows_start */
703#endif /* defined(WIN32) */
704
705static PRStatus JoinThread(PRThread *thread)
706{
707 PRStatus rv;
708 switch (thread_provider)
709 {
710 case thread_nspr:
711 rv = PR_JoinThread(thread);
712 break;
713 case thread_pthread:
714#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
715 rv = PR_SUCCESS;
716 break;
717#endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */
718 case thread_uithread:
719#if defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY)
720 rv = PR_SUCCESS;
721 break;
722#endif /* defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) */
723 case thread_win32:
724#if defined(WIN32)
725 rv = PR_SUCCESS;
726 break;
727#endif
728 default:
729 rv = PR_FAILURE;
730 break;
731 }
732 return rv;
733} /* JoinThread */
734
735static PRStatus NewThread(
736 StartFn start, void *arg, PRThreadPriority prio, PRThreadState state)
737{
738 PRStatus rv;
739
740 switch (thread_provider)
741 {
742 case thread_nspr:
743 {
744 PRThread *thread = PR_CreateThread(
745 PR_USER_THREAD, start, arg,
746 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
747 PR_JOINABLE_THREAD, 0);
748 rv = (NULL == thread) ? PR_FAILURE : PR_SUCCESS;
749 }
750 break;
751 case thread_pthread:
752#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
753 {
754 int rv;
755 pthread_t id;
756 pthread_attr_t tattr;
757 StartObject *start_object;
758 start_object = PR_NEW(StartObject);
759 PR_ASSERT(NULL != start_object);
760 start_object->start = start;
761 start_object->arg = arg;
762
763 rv = _PT_PTHREAD_ATTR_INIT(&tattr);
764 PR_ASSERT(0 == rv);
765
766 rv = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
767 PR_ASSERT(0 == rv);
768
769#if !defined(LINUX)
770 rv = pthread_attr_setstacksize(&tattr, 64 * 1024);
771 PR_ASSERT(0 == rv);
772#endif
773
774 rv = _PT_PTHREAD_CREATE(&id, tattr, pthread_start, start_object);
775 (void)_PT_PTHREAD_ATTR_DESTROY(&tattr);
776 return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
777 }
778#else
779 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
780 rv = PR_FAILURE;
781#endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */
782 break;
783
784 case thread_uithread:
785#if defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY)
786 {
787 int rv;
788 thread_t id;
789 long flags;
790 StartObject *start_object;
791 start_object = PR_NEW(StartObject);
792 PR_ASSERT(NULL != start_object);
793 start_object->start = start;
794 start_object->arg = arg;
795
796 flags = THR_DETACHED;
797
798 rv = thr_create(NULL, NULL, uithread_start, start_object, flags, &id);
799 return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
800 }
801#else
802 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
803 rv = PR_FAILURE;
804#endif /* defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) */
805 break;
806
807 case thread_sproc:
808#if defined(IRIX) && !defined(_PR_PTHREADS)
809 {
810 PRInt32 pid;
811 StartObject *start_object;
812 start_object = PR_NEW(StartObject);
813 PR_ASSERT(NULL != start_object);
814 start_object->start = start;
815 start_object->arg = arg;
816 pid = sprocsp(
817 sproc_start, PR_SALL, start_object, NULL, 64 * 1024);
818 rv = (0 < pid) ? PR_SUCCESS : PR_FAILURE;
819 }
820#else
821 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
822 rv = PR_FAILURE;
823#endif /* defined(IRIX) && !defined(_PR_PTHREADS) */
824 break;
825 case thread_win32:
826#if defined(WIN32)
827 {
828 void *th;
829 PRUintn id;
830 StartObject *start_object;
831 start_object = PR_NEW(StartObject);
832 PR_ASSERT(NULL != start_object);
833 start_object->start = start;
834 start_object->arg = arg;
835 th = (void*)_beginthreadex(
836 NULL, /* LPSECURITY_ATTRIBUTES - pointer to thread security attributes */
837 0U, /* DWORD - initial thread stack size, in bytes */
838 windows_start, /* LPTHREAD_START_ROUTINE - pointer to thread function */
839 start_object, /* LPVOID - argument for new thread */
840 0U, /*DWORD dwCreationFlags - creation flags */
841 &id /* LPDWORD - pointer to returned thread identifier */ );
842
843 rv = (NULL == th) ? PR_FAILURE : PR_SUCCESS;
844 }
845#else
846 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
847 rv = PR_FAILURE;
848#endif
849 break;
850 default:
851 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
852 rv = PR_FAILURE;
853 }
854 return rv;
855} /* NewThread */
856
857static PRStatus CreateWorker(CSServer_t *server, CSPool_t *pool)
858{
859 PRStatus rv;
860 CSWorker_t *worker = PR_NEWZAP(CSWorker_t);
861 worker->server = server;
862 PR_INIT_CLIST(&worker->element);
863 rv = NewThread(
864 Worker, worker, DEFAULT_SERVER_PRIORITY, PR_UNJOINABLE_THREAD);
865 if (PR_FAILURE == rv) PR_DELETE(worker);
866
867 TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS,
868 ("\tCreateWorker(0x%p): create new worker (0x%p)\n",
869 PR_CurrentThread(), worker->thread));
870
871 return rv;
872} /* CreateWorker */
873
874static void PR_CALLBACK Worker(void *arg)
875{
876 PRStatus rv;
877 PRNetAddr from;
878 PRFileDesc *fd = NULL;
879 CSWorker_t *worker = (CSWorker_t*)arg;
880 CSServer_t *server = worker->server;
881 CSPool_t *pool = &server->pool;
882
883 PRThread *me = worker->thread = PR_CurrentThread();
884
885 TEST_LOG(
886 cltsrv_log_file, TEST_LOG_NOTICE,
887 ("\t\tWorker(0x%p): started [%u]\n", me, pool->workers + 1));
888
889 PR_Lock(server->ml);
890 PR_APPEND_LINK(&worker->element, &server->list);
891 pool->workers += 1; /* define our existance */
892
893 while (cs_run == server->state)
894 {
895 while (pool->accepting >= server->workers.accepting)
896 {
897 TEST_LOG(
898 cltsrv_log_file, TEST_LOG_VERBOSE,
899 ("\t\tWorker(0x%p): waiting for accept slot[%d]\n",
900 me, pool->accepting));
901 rv = PR_WaitCondVar(pool->acceptComplete, PR_INTERVAL_NO_TIMEOUT);
902 if (Aborted(rv) || (cs_run != server->state))
903 {
904 TEST_LOG(
905 cltsrv_log_file, TEST_LOG_NOTICE,
906 ("\tWorker(0x%p): has been %s\n",
907 me, (Aborted(rv) ? "interrupted" : "stopped")));
908 goto exit;
909 }
910 }
911 pool->accepting += 1; /* how many are really in accept */
912 PR_Unlock(server->ml);
913
914 TEST_LOG(
915 cltsrv_log_file, TEST_LOG_VERBOSE,
916 ("\t\tWorker(0x%p): calling accept\n", me));
917 fd = PR_Accept(server->listener, &from, PR_INTERVAL_NO_TIMEOUT);
918
919 PR_Lock(server->ml);
920 pool->accepting -= 1;
921 PR_NotifyCondVar(pool->acceptComplete);
922
923 if ((NULL == fd) && Aborted(PR_FAILURE))
924 {
925 if (NULL != server->listener)
926 {
927 PR_Close(server->listener);
928 server->listener = NULL;
929 }
930 goto exit;
931 }
932
933 if (NULL != fd)
934 {
935 /*
936 ** Create another worker of the total number of workers is
937 ** less than the minimum specified or we have none left in
938 ** accept() AND we're not over the maximum.
939 ** This sort of presumes that the number allowed in accept
940 ** is at least as many as the minimum. Otherwise we'll keep
941 ** creating new threads and deleting them soon after.
942 */
943 PRBool another =
944 ((pool->workers < server->workers.minimum) ||
945 ((0 == pool->accepting)
946 && (pool->workers < server->workers.maximum))) ?
947 PR_TRUE : PR_FALSE;
948 pool->active += 1;
949 PR_Unlock(server->ml);
950
951 if (another) (void)CreateWorker(server, pool);
952
953 rv = ProcessRequest(fd, server);
954 if (PR_SUCCESS != rv)
955 TEST_LOG(
956 cltsrv_log_file, TEST_LOG_ERROR,
957 ("\t\tWorker(0x%p): server process ended abnormally\n", me));
958 (void)PR_Close(fd); fd = NULL;
959
960 PR_Lock(server->ml);
961 pool->active -= 1;
962 }
963 }
964
965exit:
966 PR_ClearInterrupt();
967 PR_Unlock(server->ml);
968
969 if (NULL != fd)
970 {
971 (void)PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
972 (void)PR_Close(fd);
973 }
974
975 TEST_LOG(
976 cltsrv_log_file, TEST_LOG_NOTICE,
977 ("\t\tWorker(0x%p): exiting [%u]\n", PR_CurrentThread(), pool->workers));
978
979 PR_Lock(server->ml);
980 pool->workers -= 1; /* undefine our existance */
981 PR_REMOVE_AND_INIT_LINK(&worker->element);
982 PR_NotifyCondVar(pool->exiting);
983 PR_Unlock(server->ml);
984
985 PR_DELETE(worker); /* destruction of the "worker" object */
986
987} /* Worker */
988
989static void PR_CALLBACK Server(void *arg)
990{
991 PRStatus rv;
992 PRNetAddr serverAddress;
993 CSServer_t *server = (CSServer_t*)arg;
994 PRThread *me = server->thread = PR_CurrentThread();
995 PRSocketOptionData sockOpt;
996
997 server->listener = PR_Socket(domain, SOCK_STREAM, protocol);
998
999 sockOpt.option = PR_SockOpt_Reuseaddr;
1000 sockOpt.value.reuse_addr = PR_TRUE;
1001 rv = PR_SetSocketOption(server->listener, &sockOpt);
1002 TEST_ASSERT(PR_SUCCESS == rv);
1003
1004 memset(&serverAddress, 0, sizeof(serverAddress));
1005 rv = PR_InitializeNetAddr(PR_IpAddrAny, DEFAULT_PORT, &serverAddress);
1006
1007 rv = PR_Bind(server->listener, &serverAddress);
1008 TEST_ASSERT(PR_SUCCESS == rv);
1009
1010 rv = PR_Listen(server->listener, server->backlog);
1011 TEST_ASSERT(PR_SUCCESS == rv);
1012
1013 server->started = PR_IntervalNow();
1014 TimeOfDayMessage("Server started at", me);
1015
1016 PR_Lock(server->ml);
1017 server->state = cs_run;
1018 PR_NotifyCondVar(server->stateChange);
1019 PR_Unlock(server->ml);
1020
1021 /*
1022 ** Create the first worker (actually, a thread that accepts
1023 ** connections and then processes the work load as needed).
1024 ** From this point on, additional worker threads are created
1025 ** as they are needed by existing worker threads.
1026 */
1027 rv = CreateWorker(server, &server->pool);
1028 TEST_ASSERT(PR_SUCCESS == rv);
1029
1030 /*
1031 ** From here on this thread is merely hanging around as the contact
1032 ** point for the main test driver. It's just waiting for the driver
1033 ** to declare the test complete.
1034 */
1035 TEST_LOG(
1036 cltsrv_log_file, TEST_LOG_VERBOSE,
1037 ("\tServer(0x%p): waiting for state change\n", me));
1038
1039 PR_Lock(server->ml);
1040 while ((cs_run == server->state) && !Aborted(rv))
1041 {
1042 rv = PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
1043 }
1044 PR_Unlock(server->ml);
1045 PR_ClearInterrupt();
1046
1047 TEST_LOG(
1048 cltsrv_log_file, TEST_LOG_INFO,
1049 ("\tServer(0x%p): shutting down workers\n", me));
1050
1051 /*
1052 ** Get all the worker threads to exit. They know how to
1053 ** clean up after themselves, so this is just a matter of
1054 ** waiting for clorine in the pool to take effect. During
1055 ** this stage we're ignoring interrupts.
1056 */
1057 server->workers.minimum = server->workers.maximum = 0;
1058
1059 PR_Lock(server->ml);
1060 while (!PR_CLIST_IS_EMPTY(&server->list))
1061 {
1062 PRCList *head = PR_LIST_HEAD(&server->list);
1063 CSWorker_t *worker = (CSWorker_t*)head;
1064 TEST_LOG(
1065 cltsrv_log_file, TEST_LOG_VERBOSE,
1066 ("\tServer(0x%p): interrupting worker(0x%p)\n", me, worker));
1067 rv = PR_Interrupt(worker->thread);
1068 TEST_ASSERT(PR_SUCCESS == rv);
1069 PR_REMOVE_AND_INIT_LINK(head);
1070 }
1071
1072 while (server->pool.workers > 0)
1073 {
1074 TEST_LOG(
1075 cltsrv_log_file, TEST_LOG_NOTICE,
1076 ("\tServer(0x%p): waiting for %u workers to exit\n",
1077 me, server->pool.workers));
1078 (void)PR_WaitCondVar(server->pool.exiting, PR_INTERVAL_NO_TIMEOUT);
1079 }
1080
1081 server->state = cs_exit;
1082 PR_NotifyCondVar(server->stateChange);
1083 PR_Unlock(server->ml);
1084
1085 TEST_LOG(
1086 cltsrv_log_file, TEST_LOG_ALWAYS,
1087 ("\tServer(0x%p): stopped after %u operations and %u bytes\n",
1088 me, server->operations, server->bytesTransferred));
1089
1090 if (NULL != server->listener) PR_Close(server->listener);
1091 server->stopped = PR_IntervalNow();
1092
1093} /* Server */
1094
1095static void WaitForCompletion(PRIntn execution)
1096{
1097 while (execution > 0)
1098 {
1099 PRIntn dally = (execution > 30) ? 30 : execution;
1100 PR_Sleep(PR_SecondsToInterval(dally));
1101 if (pthread_stats) PT_FPrintStats(debug_out, "\nPThread Statistics\n");
1102 execution -= dally;
1103 }
1104} /* WaitForCompletion */
1105
1106static void Help(void)
1107{
1108 PR_fprintf(debug_out, "cltsrv test program usage:\n");
1109 PR_fprintf(debug_out, "\t-a <n> threads allowed in accept (5)\n");
1110 PR_fprintf(debug_out, "\t-b <n> backlock for listen (5)\n");
1111 PR_fprintf(debug_out, "\t-c <threads> number of clients to create (1)\n");
1112 PR_fprintf(debug_out, "\t-w <threads> minimal number of server threads (1)\n");
1113 PR_fprintf(debug_out, "\t-W <threads> maximum number of server threads (1)\n");
1114 PR_fprintf(debug_out, "\t-e <seconds> duration of the test in seconds (10)\n");
1115 PR_fprintf(debug_out, "\t-s <string> dsn name of server (localhost)\n");
1116 PR_fprintf(debug_out, "\t-G use GLOBAL threads (LOCAL)\n");
1117 PR_fprintf(debug_out, "\t-T <string> thread provider ('n' | 'p' | 'u' | 'w')(n)\n");
1118 PR_fprintf(debug_out, "\t-X use XTP as transport (TCP)\n");
1119 PR_fprintf(debug_out, "\t-6 Use IPv6 (IPv4)\n");
1120 PR_fprintf(debug_out, "\t-v verbosity (accumulative) (0)\n");
1121 PR_fprintf(debug_out, "\t-p pthread statistics (FALSE)\n");
1122 PR_fprintf(debug_out, "\t-d debug mode (FALSE)\n");
1123 PR_fprintf(debug_out, "\t-h this message\n");
1124} /* Help */
1125
1126static Verbosity IncrementVerbosity(void)
1127{
1128 PRIntn verboge = (PRIntn)verbosity + 1;
1129 return (Verbosity)verboge;
1130} /* IncrementVerbosity */
1131
1132PRIntn main(PRIntn argc, char** argv)
1133{
1134 PRUintn index;
1135 PRBool boolean;
1136 CSClient_t *client;
1137 PRStatus rv, joinStatus;
1138 CSServer_t *server = NULL;
1139 char *thread_type;
1140
1141 PRUintn backlog = DEFAULT_BACKLOG;
1142 PRUintn clients = DEFAULT_CLIENTS;
1143 const char *serverName = DEFAULT_SERVER;
1144 PRBool serverIsLocal = PR_TRUE;
1145 PRUintn accepting = ALLOWED_IN_ACCEPT;
1146 PRUintn workersMin = DEFAULT_WORKERS_MIN;
1147 PRUintn workersMax = DEFAULT_WORKERS_MAX;
1148 PRIntn execution = DEFAULT_EXECUTION_TIME;
1149
1150 /*
1151 * -G use global threads
1152 * -a <n> threads allowed in accept
1153 * -b <n> backlock for listen
1154 * -c <threads> number of clients to create
1155 * -w <threads> minimal number of server threads
1156 * -W <threads> maximum number of server threads
1157 * -e <seconds> duration of the test in seconds
1158 * -s <string> dsn name of server (implies no server here)
1159 * -v verbosity
1160 */
1161
1162 PLOptStatus os;
1163 PLOptState *opt = PL_CreateOptState(argc, argv, "GX6b:a:c:w:W:e:s:T:vdhp");
1164
1165#if defined(WIN32)
1166 thread_provider = thread_win32;
1167#elif defined(_PR_PTHREADS)
1168 thread_provider = thread_pthread;
1169#elif defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY)
1170 thread_provider = thread_uithread;
1171#elif defined(IRIX)
1172 thread_provider = thread_sproc;
1173#else
1174 thread_provider = thread_nspr;
1175#endif
1176
1177 debug_out = PR_GetSpecialFD(PR_StandardError);
1178
1179 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
1180 {
1181 if (PL_OPT_BAD == os) continue;
1182 switch (opt->option)
1183 {
1184 case 'G': /* use global threads */
1185 thread_scope = PR_GLOBAL_THREAD;
1186 break;
1187 case 'X': /* use XTP as transport */
1188 protocol = 36;
1189 break;
1190 case '6': /* Use IPv6 */
1191 domain = PR_AF_INET6;
1192 break;
1193 case 'a': /* the value for accepting */
1194 accepting = atoi(opt->value);
1195 break;
1196 case 'b': /* the value for backlock */
1197 backlog = atoi(opt->value);
1198 break;
1199 case 'T': /* the thread provider */
1200 if ('n' == *opt->value) thread_provider = thread_nspr;
1201 else if ('p' == *opt->value) thread_provider = thread_pthread;
1202 else if ('u' == *opt->value) thread_provider = thread_uithread;
1203 else if ('w' == *opt->value) thread_provider = thread_win32;
1204 else {Help(); return 2; }
1205 break;
1206 case 'c': /* number of client threads */
1207 clients = atoi(opt->value);
1208 break;
1209 case 'w': /* minimum server worker threads */
1210 workersMin = atoi(opt->value);
1211 break;
1212 case 'W': /* maximum server worker threads */
1213 workersMax = atoi(opt->value);
1214 break;
1215 case 'e': /* program execution time in seconds */
1216 execution = atoi(opt->value);
1217 break;
1218 case 's': /* server's address */
1219 serverName = opt->value;
1220 break;
1221 case 'v': /* verbosity */
1222 verbosity = IncrementVerbosity();
1223 break;
1224 case 'd': /* debug mode */
1225 debug_mode = PR_TRUE;
1226 break;
1227 case 'p': /* pthread mode */
1228 pthread_stats = PR_TRUE;
1229 break;
1230 case 'h':
1231 default:
1232 Help();
1233 return 2;
1234 }
1235 }
1236 PL_DestroyOptState(opt);
1237
1238 if (0 != PL_strcmp(serverName, DEFAULT_SERVER)) serverIsLocal = PR_FALSE;
1239 if (0 == execution) execution = DEFAULT_EXECUTION_TIME;
1240 if (0 == workersMax) workersMax = DEFAULT_WORKERS_MAX;
1241 if (0 == workersMin) workersMin = DEFAULT_WORKERS_MIN;
1242 if (0 == accepting) accepting = ALLOWED_IN_ACCEPT;
1243 if (0 == backlog) backlog = DEFAULT_BACKLOG;
1244
1245 if (workersMin > accepting) accepting = workersMin;
1246
1247 PR_STDIO_INIT();
1248 TimeOfDayMessage("Client/Server started at", PR_CurrentThread());
1249
1250 cltsrv_log_file = PR_NewLogModule("cltsrv_log");
1251 MY_ASSERT(NULL != cltsrv_log_file);
1252 boolean = PR_SetLogFile("cltsrv.log");
1253 MY_ASSERT(boolean);
1254
1255#ifdef XP_MAC
1256 debug_mode = PR_TRUE;
1257#endif
1258
1259 if (serverIsLocal)
1260 {
1261 /* Establish the server */
1262 TEST_LOG(
1263 cltsrv_log_file, TEST_LOG_INFO,
1264 ("main(0x%p): starting server\n", PR_CurrentThread()));
1265
1266 server = PR_NEWZAP(CSServer_t);
1267 PR_INIT_CLIST(&server->list);
1268 server->state = cs_init;
1269 server->ml = PR_NewLock();
1270 server->backlog = backlog;
1271 server->port = DEFAULT_PORT;
1272 server->workers.minimum = workersMin;
1273 server->workers.maximum = workersMax;
1274 server->workers.accepting = accepting;
1275 server->stateChange = PR_NewCondVar(server->ml);
1276 server->pool.exiting = PR_NewCondVar(server->ml);
1277 server->pool.acceptComplete = PR_NewCondVar(server->ml);
1278
1279 TEST_LOG(
1280 cltsrv_log_file, TEST_LOG_NOTICE,
1281 ("main(0x%p): creating server thread\n", PR_CurrentThread()));
1282
1283 rv = NewThread(
1284 Server, server, PR_PRIORITY_HIGH, PR_JOINABLE_THREAD);
1285 TEST_ASSERT(PR_SUCCESS == rv);
1286
1287 TEST_LOG(
1288 cltsrv_log_file, TEST_LOG_VERBOSE,
1289 ("main(0x%p): waiting for server init\n", PR_CurrentThread()));
1290
1291 PR_Lock(server->ml);
1292 while (server->state == cs_init)
1293 PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
1294 PR_Unlock(server->ml);
1295
1296 TEST_LOG(
1297 cltsrv_log_file, TEST_LOG_VERBOSE,
1298 ("main(0x%p): server init complete (port #%d)\n",
1299 PR_CurrentThread(), server->port));
1300 }
1301
1302 if (clients != 0)
1303 {
1304 /* Create all of the clients */
1305 PRHostEnt host;
1306 char buffer[BUFFER_SIZE];
1307 client = (CSClient_t*)PR_CALLOC(clients * sizeof(CSClient_t));
1308
1309 TEST_LOG(
1310 cltsrv_log_file, TEST_LOG_VERBOSE,
1311 ("main(0x%p): creating %d client threads\n",
1312 PR_CurrentThread(), clients));
1313
1314 if (!serverIsLocal)
1315 {
1316 rv = PR_GetHostByName(serverName, buffer, BUFFER_SIZE, &host);
1317 if (PR_SUCCESS != rv)
1318 {
1319 PL_FPrintError(PR_STDERR, "PR_GetHostByName");
1320 return 2;
1321 }
1322 }
1323
1324 for (index = 0; index < clients; ++index)
1325 {
1326 client[index].state = cs_init;
1327 client[index].ml = PR_NewLock();
1328 if (serverIsLocal)
1329 {
1330 (void)PR_InitializeNetAddr(
1331 PR_IpAddrLoopback, DEFAULT_PORT,
1332 &client[index].serverAddress);
1333 }
1334 else
1335 {
1336 (void)PR_EnumerateHostEnt(
1337 0, &host, DEFAULT_PORT, &client[index].serverAddress);
1338 }
1339 client[index].stateChange = PR_NewCondVar(client[index].ml);
1340 TEST_LOG(
1341 cltsrv_log_file, TEST_LOG_INFO,
1342 ("main(0x%p): creating client threads\n", PR_CurrentThread()));
1343 rv = NewThread(
1344 Client, &client[index], PR_PRIORITY_NORMAL, PR_JOINABLE_THREAD);
1345 TEST_ASSERT(PR_SUCCESS == rv);
1346 PR_Lock(client[index].ml);
1347 while (cs_init == client[index].state)
1348 PR_WaitCondVar(client[index].stateChange, PR_INTERVAL_NO_TIMEOUT);
1349 PR_Unlock(client[index].ml);
1350 }
1351 }
1352
1353 /* Then just let them go at it for a bit */
1354 TEST_LOG(
1355 cltsrv_log_file, TEST_LOG_ALWAYS,
1356 ("main(0x%p): waiting for execution interval (%d seconds)\n",
1357 PR_CurrentThread(), execution));
1358
1359 WaitForCompletion(execution);
1360
1361 TimeOfDayMessage("Shutting down", PR_CurrentThread());
1362
1363 if (clients != 0)
1364 {
1365 for (index = 0; index < clients; ++index)
1366 {
1367 TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS,
1368 ("main(0x%p): notifying client(0x%p) to stop\n",
1369 PR_CurrentThread(), client[index].thread));
1370
1371 PR_Lock(client[index].ml);
1372 if (cs_run == client[index].state)
1373 {
1374 client[index].state = cs_stop;
1375 PR_Interrupt(client[index].thread);
1376 while (cs_stop == client[index].state)
1377 PR_WaitCondVar(
1378 client[index].stateChange, PR_INTERVAL_NO_TIMEOUT);
1379 }
1380 PR_Unlock(client[index].ml);
1381
1382 TEST_LOG(cltsrv_log_file, TEST_LOG_VERBOSE,
1383 ("main(0x%p): joining client(0x%p)\n",
1384 PR_CurrentThread(), client[index].thread));
1385
1386 joinStatus = JoinThread(client[index].thread);
1387 TEST_ASSERT(PR_SUCCESS == joinStatus);
1388 PR_DestroyCondVar(client[index].stateChange);
1389 PR_DestroyLock(client[index].ml);
1390 }
1391 PR_DELETE(client);
1392 }
1393
1394 if (NULL != server)
1395 {
1396 /* All clients joined - retrieve the server */
1397 TEST_LOG(
1398 cltsrv_log_file, TEST_LOG_NOTICE,
1399 ("main(0x%p): notifying server(0x%p) to stop\n",
1400 PR_CurrentThread(), server->thread));
1401
1402 PR_Lock(server->ml);
1403 server->state = cs_stop;
1404 PR_Interrupt(server->thread);
1405 while (cs_exit != server->state)
1406 PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
1407 PR_Unlock(server->ml);
1408
1409 TEST_LOG(
1410 cltsrv_log_file, TEST_LOG_NOTICE,
1411 ("main(0x%p): joining server(0x%p)\n",
1412 PR_CurrentThread(), server->thread));
1413 joinStatus = JoinThread(server->thread);
1414 TEST_ASSERT(PR_SUCCESS == joinStatus);
1415
1416 PR_DestroyCondVar(server->stateChange);
1417 PR_DestroyCondVar(server->pool.exiting);
1418 PR_DestroyCondVar(server->pool.acceptComplete);
1419 PR_DestroyLock(server->ml);
1420 PR_DELETE(server);
1421 }
1422
1423 TEST_LOG(
1424 cltsrv_log_file, TEST_LOG_ALWAYS,
1425 ("main(0x%p): test complete\n", PR_CurrentThread()));
1426
1427 if (thread_provider == thread_win32)
1428 thread_type = "\nWin32 Thread Statistics\n";
1429 else if (thread_provider == thread_pthread)
1430 thread_type = "\npthread Statistics\n";
1431 else if (thread_provider == thread_uithread)
1432 thread_type = "\nUnix International (UI) Thread Statistics\n";
1433 else if (thread_provider == thread_sproc)
1434 thread_type = "\nsproc Statistics\n";
1435 else {
1436 PR_ASSERT(thread_provider == thread_nspr);
1437 thread_type = "\nPRThread Statistics\nn";
1438 }
1439
1440 PT_FPrintStats(debug_out, thread_type);
1441
1442 TimeOfDayMessage("Test exiting at", PR_CurrentThread());
1443 PR_Cleanup();
1444 return 0;
1445} /* main */
1446
1447/* cltsrv.c */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette