home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / tests / server_test.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  17.6 KB  |  618 lines

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