nsprpub/pr/tests/provider.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial