nsprpub/pr/tests/server_test.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 ** This server simulates a server running in loopback mode.
     9 **
    10 ** The idea is that a single server is created.  The server initially creates
    11 ** a number of worker threads.  Then, with the server running, a number of 
    12 ** clients are created which start requesting service from the server.
    13 **
    14 **
    15 ** Modification History:
    16 ** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
    17 **	         The debug mode will print all of the printfs associated with this test.
    18 **			 The regress mode will be the default mode. Since the regress tool limits
    19 **           the output to a one line status:PASS or FAIL,all of the printf statements
    20 **			 have been handled with an if (debug_mode) statement. 
    21 ***********************************************************************/
    23 /***********************************************************************
    24 ** Includes
    25 ***********************************************************************/
    26 /* Used to get the command line option */
    27 #include "plgetopt.h"
    29 #include "nspr.h"
    30 #include "pprthred.h"
    32 #include <string.h>
    34 #define PORT 15004
    35 #define THREAD_STACKSIZE 0
    37 #define PASS 0
    38 #define FAIL 1
    39 static int debug_mode = 0;
    41 static int _iterations = 1000;
    42 static int _clients = 1;
    43 static int _client_data = 250;
    44 static int _server_data = (8*1024);
    46 static PRThreadScope ServerScope, ClientScope;
    48 #define SERVER "Server"
    49 #define MAIN   "Main"
    51 #define SERVER_STATE_STARTUP 0
    52 #define SERVER_STATE_READY   1
    53 #define SERVER_STATE_DYING   2
    54 #define SERVER_STATE_DEAD    4
    55 int       ServerState;
    56 PRLock    *ServerStateCVLock;
    57 PRCondVar *ServerStateCV;
    59 #undef DEBUGPRINTS
    60 #ifdef DEBUGPRINTS
    61 #define DPRINTF printf
    62 #else
    63 #define DPRINTF
    64 #endif
    67 /***********************************************************************
    68 ** PRIVATE FUNCTION:    Test_Result
    69 ** DESCRIPTION: Used in conjunction with the regress tool, prints out the
    70 **				status of the test case.
    71 ** INPUTS:      PASS/FAIL
    72 ** OUTPUTS:     None
    73 ** RETURN:      None
    74 ** SIDE EFFECTS:
    75 **      
    76 ** RESTRICTIONS:
    77 **      None
    78 ** MEMORY:      NA
    79 ** ALGORITHM:   Determine what the status is and print accordingly.
    80 **      
    81 ***********************************************************************/
    84 static void Test_Result (int result)
    85 {
    86 	switch (result)
    87 	{
    88 		case PASS:
    89 			printf ("PASS\n");
    90 			break;
    91 		case FAIL:
    92 			printf ("FAIL\n");
    93 			break;
    94 		default:
    95 			break;
    96 	}
    97 }
    99 static void do_work(void);
   101 /* --- Server state functions --------------------------------------------- */
   102 void
   103 SetServerState(char *waiter, PRInt32 state)
   104 {
   105     PR_Lock(ServerStateCVLock);
   106     ServerState = state;
   107     PR_NotifyCondVar(ServerStateCV);
   109 	if (debug_mode) DPRINTF("\t%s changed state to %d\n", waiter, state);
   111     PR_Unlock(ServerStateCVLock);
   112 }
   114 int
   115 WaitServerState(char *waiter, PRInt32 state)
   116 {
   117     PRInt32 rv;
   119     PR_Lock(ServerStateCVLock);
   121     if (debug_mode) DPRINTF("\t%s waiting for state %d\n", waiter, state);
   123     while(!(ServerState & state))
   124         PR_WaitCondVar(ServerStateCV, PR_INTERVAL_NO_TIMEOUT);
   125     rv = ServerState;
   127     if (debug_mode) DPRINTF("\t%s resuming from wait for state %d; state now %d\n", 
   128         waiter, state, ServerState);
   129     PR_Unlock(ServerStateCVLock);
   131     return rv;
   132 }
   134 /* --- Server Functions ------------------------------------------- */
   136 PRLock *workerThreadsLock;
   137 PRInt32 workerThreads;
   138 PRInt32 workerThreadsBusy;
   140 void
   141 WorkerThreadFunc(void *_listenSock)
   142 {
   143     PRFileDesc *listenSock = (PRFileDesc *)_listenSock;
   144     PRInt32 bytesRead;
   145     PRInt32 bytesWritten;
   146     char *dataBuf;
   147     char *sendBuf;
   149     if (debug_mode) DPRINTF("\tServer buffer is %d bytes; %d data, %d netaddrs\n",
   150             _client_data+(2*sizeof(PRNetAddr))+32, _client_data, (2*sizeof(PRNetAddr))+32);
   151     dataBuf = (char *)PR_MALLOC(_client_data + 2*sizeof(PRNetAddr) + 32);
   152     if (!dataBuf)
   153         if (debug_mode) printf("\tServer could not malloc space!?\n");
   154     sendBuf = (char *)PR_MALLOC(_server_data *sizeof(char));
   155     if (!sendBuf)
   156         if (debug_mode) printf("\tServer could not malloc space!?\n");
   158     if (debug_mode) DPRINTF("\tServer worker thread running\n");
   160     while(1) {
   161         PRInt32 bytesToRead = _client_data;
   162         PRInt32 bytesToWrite = _server_data;
   163         PRFileDesc *newSock;
   164         PRNetAddr *rAddr;
   165         PRInt32 loops = 0;
   167         loops++;
   169         if (debug_mode) DPRINTF("\tServer thread going into accept\n");
   171         bytesRead = PR_AcceptRead(listenSock, 
   172                                   &newSock,
   173                                   &rAddr,
   174                                   dataBuf,
   175                                   bytesToRead,
   176                                   PR_INTERVAL_NO_TIMEOUT);
   178         if (bytesRead < 0) {
   179             if (debug_mode) printf("\tServer error in accept (%d)\n", bytesRead);
   180             continue;
   181         }
   183         if (debug_mode) DPRINTF("\tServer accepted connection (%d bytes)\n", bytesRead);
   185         PR_AtomicIncrement(&workerThreadsBusy);
   186 #ifdef SYMBIAN
   187         if (workerThreadsBusy == workerThreads && workerThreads<1) {
   188 #else
   189         if (workerThreadsBusy == workerThreads) {
   190 #endif
   191             PR_Lock(workerThreadsLock);
   192             if (workerThreadsBusy == workerThreads) {
   193                 PRThread *WorkerThread;
   195                 WorkerThread = PR_CreateThread(
   196                                   PR_SYSTEM_THREAD,
   197                                   WorkerThreadFunc,
   198                                   listenSock,
   199                                   PR_PRIORITY_NORMAL,
   200                                   ServerScope,
   201                                   PR_UNJOINABLE_THREAD,
   202                                   THREAD_STACKSIZE);
   204                 if (!WorkerThread) {
   205                     if (debug_mode) printf("Error creating client thread %d\n", workerThreads);
   206                 } else {
   207                     PR_AtomicIncrement(&workerThreads);
   208                     if (debug_mode) DPRINTF("\tServer creates worker (%d)\n", workerThreads);
   209                 }
   210             }
   211             PR_Unlock(workerThreadsLock);
   212         }
   214         bytesToRead -= bytesRead;
   215         while (bytesToRead) {
   216             bytesRead = PR_Recv(newSock, 
   217                                 dataBuf, 
   218                                 bytesToRead, 
   219                                 0, 
   220                                 PR_INTERVAL_NO_TIMEOUT);
   221             if (bytesRead < 0) {
   222                 if (debug_mode) printf("\tServer error receiving data (%d)\n", bytesRead);
   223                 continue;
   224             }
   225             if (debug_mode) DPRINTF("\tServer received %d bytes\n", bytesRead);
   226         }
   228         bytesWritten = PR_Send(newSock,
   229                                sendBuf, 
   230                                bytesToWrite, 
   231                                0, 
   232                                PR_INTERVAL_NO_TIMEOUT);
   233         if (bytesWritten != _server_data) {
   234             if (debug_mode) printf("\tError sending data to client (%d, %d)\n", 
   235                 bytesWritten, PR_GetOSError());
   236         } else {
   237             if (debug_mode) DPRINTF("\tServer sent %d bytes\n", bytesWritten);
   238         }	
   240         PR_Close(newSock);
   241         PR_AtomicDecrement(&workerThreadsBusy);
   242     }
   243 }
   245 PRFileDesc *
   246 ServerSetup(void)
   247 {
   248     PRFileDesc *listenSocket;
   249     PRNetAddr serverAddr;
   250     PRThread *WorkerThread;
   252     if ( (listenSocket = PR_NewTCPSocket()) == NULL) {
   253         if (debug_mode) printf("\tServer error creating listen socket\n");
   254 		else Test_Result(FAIL);
   255         return NULL;
   256     }
   258     memset(&serverAddr, 0, sizeof(PRNetAddr));
   259     serverAddr.inet.family = PR_AF_INET;
   260     serverAddr.inet.port = PR_htons(PORT);
   261     serverAddr.inet.ip = PR_htonl(PR_INADDR_ANY);
   263     if ( PR_Bind(listenSocket, &serverAddr) == PR_FAILURE) {
   264         if (debug_mode) printf("\tServer error binding to server address: OS error %d\n",
   265                 PR_GetOSError());
   266 		else Test_Result(FAIL);
   267         PR_Close(listenSocket);
   268         return NULL;
   269     }
   271     if ( PR_Listen(listenSocket, 128) == PR_FAILURE) {
   272         if (debug_mode) printf("\tServer error listening to server socket\n");
   273 		else Test_Result(FAIL);
   274         PR_Close(listenSocket);
   276         return NULL;
   277     }
   279     /* Create Clients */
   280     workerThreads = 0;
   281     workerThreadsBusy = 0;
   283     workerThreadsLock = PR_NewLock();
   285     WorkerThread = PR_CreateThread(
   286                       PR_SYSTEM_THREAD,
   287                       WorkerThreadFunc,
   288                       listenSocket,
   289                       PR_PRIORITY_NORMAL,
   290                       ServerScope,
   291                       PR_UNJOINABLE_THREAD,
   292                       THREAD_STACKSIZE);
   294     if (!WorkerThread) {
   295         if (debug_mode) printf("error creating working thread\n");
   296         PR_Close(listenSocket);
   297         return NULL;
   298     }
   299     PR_AtomicIncrement(&workerThreads);
   300     if (debug_mode) DPRINTF("\tServer created primordial worker thread\n");
   302     return listenSocket;
   303 }
   305 /* The main server loop */
   306 void
   307 ServerThreadFunc(void *unused)
   308 {
   309     PRFileDesc *listenSocket;
   311     /* Do setup */
   312     listenSocket = ServerSetup();
   314     if (!listenSocket) {
   315         SetServerState(SERVER, SERVER_STATE_DEAD);
   316     } else {
   318         if (debug_mode) DPRINTF("\tServer up\n");
   320         /* Tell clients they can start now. */
   321         SetServerState(SERVER, SERVER_STATE_READY);
   323         /* Now wait for server death signal */
   324         WaitServerState(SERVER, SERVER_STATE_DYING);
   326         /* Cleanup */
   327         SetServerState(SERVER, SERVER_STATE_DEAD);
   328     }
   329 }
   331 /* --- Client Functions ------------------------------------------- */
   333 PRInt32 numRequests;
   334 PRInt32 numClients;
   335 PRMonitor *clientMonitor;
   337 void
   338 ClientThreadFunc(void *unused)
   339 {
   340     PRNetAddr serverAddr;
   341     PRFileDesc *clientSocket;
   342     char *sendBuf;
   343     char *recvBuf;
   344     PRInt32 rv;
   345     PRInt32 bytesNeeded;
   347     sendBuf = (char *)PR_MALLOC(_client_data * sizeof(char));
   348     if (!sendBuf)
   349         if (debug_mode) printf("\tClient could not malloc space!?\n");
   350     recvBuf = (char *)PR_MALLOC(_server_data * sizeof(char));
   351     if (!recvBuf)
   352         if (debug_mode) printf("\tClient could not malloc space!?\n");
   354     memset(&serverAddr, 0, sizeof(PRNetAddr));
   355     serverAddr.inet.family = PR_AF_INET;
   356     serverAddr.inet.port = PR_htons(PORT);
   357     serverAddr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
   359     while(numRequests > 0) {
   361         if ( (numRequests % 10) == 0 )
   362             if (debug_mode) printf(".");
   363         if (debug_mode) DPRINTF("\tClient starting request %d\n", numRequests);
   365         clientSocket = PR_NewTCPSocket();
   366         if (!clientSocket) {
   367             if (debug_mode) printf("Client error creating socket: OS error %d\n",
   368 		    PR_GetOSError());
   369             continue;
   370         }
   372         if (debug_mode) DPRINTF("\tClient connecting\n");
   374         rv = PR_Connect(clientSocket, 
   375                         &serverAddr,
   376                         PR_INTERVAL_NO_TIMEOUT);
   377         if (!clientSocket) {
   378             if (debug_mode) printf("\tClient error connecting\n");
   379             continue;
   380         }
   382         if (debug_mode) DPRINTF("\tClient connected\n");
   384         rv = PR_Send(clientSocket, 
   385                      sendBuf, 
   386                      _client_data, 
   387                      0, 
   388                      PR_INTERVAL_NO_TIMEOUT);
   389         if (rv != _client_data) {
   390             if (debug_mode) printf("Client error sending data (%d)\n", rv);
   391             PR_Close(clientSocket);
   392             continue;
   393         }
   395         if (debug_mode) DPRINTF("\tClient sent %d bytes\n", rv);
   397         bytesNeeded = _server_data;
   398         while(bytesNeeded) {
   399             rv = PR_Recv(clientSocket, 
   400                          recvBuf, 
   401                          bytesNeeded, 
   402                          0, 
   403                          PR_INTERVAL_NO_TIMEOUT);
   404             if (rv <= 0) {
   405                 if (debug_mode) printf("Client error receiving data (%d) (%d/%d)\n", 
   406                     rv, (_server_data - bytesNeeded), _server_data);
   407                 break;
   408             }
   409             if (debug_mode) DPRINTF("\tClient received %d bytes; need %d more\n", rv, bytesNeeded - rv);
   410             bytesNeeded -= rv;
   411         }
   413         PR_Close(clientSocket);
   415         PR_AtomicDecrement(&numRequests);
   416     }
   418     PR_EnterMonitor(clientMonitor);
   419     --numClients;
   420     PR_Notify(clientMonitor);
   421     PR_ExitMonitor(clientMonitor);
   423     PR_DELETE(sendBuf);
   424     PR_DELETE(recvBuf);
   425 }
   427 void
   428 RunClients(void)
   429 {
   430     PRInt32 index;
   432     numRequests = _iterations;
   433     numClients = _clients;
   434     clientMonitor = PR_NewMonitor();
   436     for (index=0; index<_clients; index++) {
   437         PRThread *clientThread;
   440         clientThread = PR_CreateThread(
   441                           PR_USER_THREAD,
   442                           ClientThreadFunc,
   443                           NULL,
   444                           PR_PRIORITY_NORMAL,
   445                           ClientScope,
   446                           PR_UNJOINABLE_THREAD,
   447                           THREAD_STACKSIZE);
   449         if (!clientThread) {
   450             if (debug_mode) printf("\terror creating client thread %d\n", index);
   451         } else
   452             if (debug_mode) DPRINTF("\tMain created client %d/%d\n", index+1, _clients);
   454     }
   456     PR_EnterMonitor(clientMonitor);
   457     while(numClients)
   458         PR_Wait(clientMonitor, PR_INTERVAL_NO_TIMEOUT);
   459     PR_ExitMonitor(clientMonitor);
   460 }
   462 /* --- Main Function ---------------------------------------------- */
   464 static
   465 void do_work()
   466 {
   467     PRThread *ServerThread;
   468     PRInt32 state;
   470     SetServerState(MAIN, SERVER_STATE_STARTUP);
   471     ServerThread = PR_CreateThread(
   472                       PR_USER_THREAD,
   473                       ServerThreadFunc,
   474                       NULL,
   475                       PR_PRIORITY_NORMAL,
   476                       ServerScope,
   477                       PR_JOINABLE_THREAD,
   478                       THREAD_STACKSIZE);
   479     if (!ServerThread) {
   480         if (debug_mode) printf("error creating main server thread\n");
   481         return;
   482     }
   484     /* Wait for server to be ready */
   485     state = WaitServerState(MAIN, SERVER_STATE_READY|SERVER_STATE_DEAD);
   487     if (!(state & SERVER_STATE_DEAD)) {
   488         /* Run Test Clients */
   489         RunClients();
   491         /* Send death signal to server */
   492         SetServerState(MAIN, SERVER_STATE_DYING);
   493     }
   495     PR_JoinThread(ServerThread);
   496 }
   498 static void do_workUU(void)
   499 {
   500     ServerScope = PR_LOCAL_THREAD;
   501     ClientScope = PR_LOCAL_THREAD;
   502     do_work();
   503 }
   505 static void do_workUK(void)
   506 {
   507     ServerScope = PR_LOCAL_THREAD;
   508     ClientScope = PR_GLOBAL_THREAD;
   509     do_work();
   510 }
   512 static void do_workKU(void)
   513 {
   514     ServerScope = PR_GLOBAL_THREAD;
   515     ClientScope = PR_LOCAL_THREAD;
   516     do_work();
   517 }
   519 static void do_workKK(void)
   520 {
   521     ServerScope = PR_GLOBAL_THREAD;
   522     ClientScope = PR_GLOBAL_THREAD;
   523     do_work();
   524 }
   527 static void Measure(void (*func)(void), const char *msg)
   528 {
   529     PRIntervalTime start, stop;
   530     double d;
   532     start = PR_IntervalNow();
   533     (*func)();
   534     stop = PR_IntervalNow();
   536     d = (double)PR_IntervalToMicroseconds(stop - start);
   538     if (debug_mode) printf("\n%40s: %6.2f usec\n", msg, d / _iterations);
   539 }
   542 int main(int argc, char **argv)
   543 {
   544 	/* The command line argument: -d is used to determine if the test is being run
   545 	in debug mode. The regress tool requires only one line output:PASS or FAIL.
   546 	All of the printfs associated with this test has been handled with a if (debug_mode)
   547 	test.
   548 	Usage: test_name -d
   549 	*/
   550 	PLOptStatus os;
   551 	PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
   552 	while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
   553     {
   554 		if (PL_OPT_BAD == os) continue;
   555         switch (opt->option)
   556         {
   557         case 'd':  /* debug mode */
   558 			debug_mode = 1;
   559             break;
   560          default:
   561             break;
   562         }
   563     }
   564 	PL_DestroyOptState(opt);
   566  /* main test */
   567 #ifndef SYMBIAN
   568     if (debug_mode) {
   569 		printf("Enter number of iterations: \n");
   570 		scanf("%d", &_iterations);
   571 		printf("Enter number of clients   : \n");
   572 		scanf("%d", &_clients);
   573 		printf("Enter size of client data : \n");
   574 		scanf("%d", &_client_data);
   575 		printf("Enter size of server data : \n");
   576 		scanf("%d", &_server_data);
   577 	}
   578 	else 
   579 #endif
   580 	{
   582 		_iterations = 10;
   583 	    _clients = 1;
   584 		_client_data = 10;
   585 		_server_data = 10;
   586 	}
   588     if (debug_mode) {
   589 		printf("\n\n%d iterations with %d client threads.\n", 
   590         _iterations, _clients);
   591 		printf("Sending %d bytes of client data and %d bytes of server data\n", 
   592         _client_data, _server_data);
   593 	}
   594     PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
   595     PR_STDIO_INIT();
   597     ServerStateCVLock = PR_NewLock();
   598     ServerStateCV = PR_NewCondVar(ServerStateCVLock);
   600     Measure(do_workUU, "server loop user/user");
   601  #if 0 
   602     Measure(do_workUK, "server loop user/kernel");
   603     Measure(do_workKU, "server loop kernel/user");
   604     Measure(do_workKK, "server loop kernel/kernel");
   605  #endif 
   607     PR_Cleanup();
   609     return 0;
   610 }

mercurial