home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / tests / servr_uk.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  16.5 KB  |  567 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. ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
  35. **            recognize the return code from tha main program.
  36. ***********************************************************************/
  37.  
  38. /***********************************************************************
  39. ** Includes
  40. ***********************************************************************/
  41. /* Used to get the command line option */
  42. #include "plgetopt.h"
  43.  
  44. #include "nspr.h"
  45. #include "pprthred.h"
  46.  
  47. #include <string.h>
  48.  
  49. #define PORT 15004
  50. #define STACKSIZE 0
  51.  
  52. static int _iterations = 1000;
  53. static int _clients = 1;
  54. static int _client_data = 250;
  55. static int _server_data = (8*1024);
  56.  
  57. static PRThreadScope ServerScope, ClientScope;
  58.  
  59. #define SERVER "Server"
  60. #define MAIN   "Main"
  61.  
  62. #define SERVER_STATE_STARTUP 0
  63. #define SERVER_STATE_READY   1
  64. #define SERVER_STATE_DYING   2
  65. #define SERVER_STATE_DEAD    4
  66. int       ServerState;
  67. PRLock    *ServerStateCVLock;
  68. PRCondVar *ServerStateCV;
  69.  
  70. #undef DEBUGPRINTS
  71. #ifdef DEBUGPRINTS
  72. #define DPRINTF printf
  73. #else
  74. #define DPRINTF
  75. #endif
  76.  
  77. PRIntn failed_already=0;
  78. PRIntn debug_mode;
  79.  
  80.  
  81.  
  82. static void do_work(void);
  83.  
  84. /* --- Server state functions --------------------------------------------- */
  85. void
  86. SetServerState(char *waiter, PRInt32 state)
  87. {
  88.     PR_Lock(ServerStateCVLock);
  89.     ServerState = state;
  90.     PR_NotifyCondVar(ServerStateCV);
  91.  
  92.     if (debug_mode) DPRINTF("\t%s changed state to %d\n", waiter, state);
  93.  
  94.     PR_Unlock(ServerStateCVLock);
  95. }
  96.  
  97. int
  98. WaitServerState(char *waiter, PRInt32 state)
  99. {
  100.     PRInt32 rv;
  101.  
  102.     PR_Lock(ServerStateCVLock);
  103.  
  104.     if (debug_mode) DPRINTF("\t%s waiting for state %d\n", waiter, state);
  105.  
  106.     while(!(ServerState & state))
  107.         PR_WaitCondVar(ServerStateCV, PR_INTERVAL_NO_TIMEOUT);
  108.     rv = ServerState;
  109.  
  110.     if (debug_mode) DPRINTF("\t%s resuming from wait for state %d; state now %d\n", 
  111.         waiter, state, ServerState);
  112.     PR_Unlock(ServerStateCVLock);
  113.  
  114.     return rv;
  115. }
  116.  
  117. /* --- Server Functions ------------------------------------------- */
  118.  
  119. PRLock *workerThreadsLock;
  120. PRInt32 workerThreads;
  121. PRInt32 workerThreadsBusy;
  122.  
  123. void
  124. WorkerThreadFunc(void *_listenSock)
  125. {
  126.     PRFileDesc *listenSock = (PRFileDesc *)_listenSock;
  127.     PRInt32 bytesRead;
  128.     PRInt32 bytesWritten;
  129.     char *dataBuf;
  130.     char *sendBuf;
  131.  
  132.     if (debug_mode) DPRINTF("\tServer buffer is %d bytes; %d data, %d netaddrs\n",
  133.             _client_data+(4*sizeof(PRNetAddr)), _client_data, (4*sizeof(PRNetAddr)));
  134.     dataBuf = (char *)PR_MALLOC(_client_data *sizeof(char) + 4*sizeof(PRNetAddr));
  135.     if (!dataBuf)
  136.         if (debug_mode) printf("\tServer could not malloc space!?\n");
  137.     sendBuf = (char *)PR_MALLOC(_server_data *sizeof(char));
  138.     if (!sendBuf)
  139.         if (debug_mode) printf("\tServer could not malloc space!?\n");
  140.  
  141.     if (debug_mode) DPRINTF("\tServer worker thread running\n");
  142.  
  143.     while(1) {
  144.         PRInt32 bytesToRead = _client_data;
  145.         PRInt32 bytesToWrite = _server_data;
  146.         PRFileDesc *newSock;
  147.         PRNetAddr *rAddr;
  148.         PRInt32 loops = 0;
  149.  
  150.         loops++;
  151.  
  152.         if (debug_mode) DPRINTF("\tServer thread going into accept\n");
  153.  
  154.         bytesRead = PR_AcceptRead(listenSock, 
  155.                                   &newSock,
  156.                                   &rAddr,
  157.                                   dataBuf,
  158.                                   bytesToRead,
  159.                                   PR_INTERVAL_NO_TIMEOUT);
  160.  
  161.         if (bytesRead < 0) {
  162.             if (debug_mode) printf("\tServer error in accept (%d)\n", bytesRead);
  163.             continue;
  164.         }
  165.  
  166.         if (debug_mode) DPRINTF("\tServer accepted connection (%d bytes)\n", bytesRead);
  167.         
  168.         PR_AtomicIncrement(&workerThreadsBusy);
  169.         if (workerThreadsBusy == workerThreads) {
  170.  
  171.             PR_Lock(workerThreadsLock);
  172.             if (workerThreadsBusy == workerThreads) {
  173.                 PRThread *WorkerThread;
  174.  
  175.                 WorkerThread = PR_CreateThread(
  176.                                   PR_SYSTEM_THREAD,
  177.                                   WorkerThreadFunc,
  178.                                   listenSock,
  179.                                   PR_PRIORITY_NORMAL,
  180.                                   ServerScope,
  181.                                   PR_UNJOINABLE_THREAD,
  182.                                   STACKSIZE);
  183.  
  184.                 if (!WorkerThread)
  185.                     if (debug_mode) printf("Error creating client thread %d\n", workerThreads);
  186.                 else {
  187.                     PR_AtomicIncrement(&workerThreads);
  188.                     if (debug_mode) DPRINTF("\tServer creates worker (%d)\n", workerThreads);
  189.                 }
  190.             }
  191.             PR_Unlock(workerThreadsLock);
  192.         }
  193.  
  194.         bytesToRead -= bytesRead;
  195.         while (bytesToRead) {
  196.             bytesRead = PR_Recv(newSock, 
  197.                                 dataBuf, 
  198.                                 bytesToRead, 
  199.                                 0, 
  200.                                 PR_INTERVAL_NO_TIMEOUT);
  201.             if (bytesRead < 0) {
  202.                 if (debug_mode) printf("\tServer error receiving data (%d)\n", bytesRead);
  203.                 continue;
  204.             }
  205.             if (debug_mode) DPRINTF("\tServer received %d bytes\n", bytesRead);
  206.         }
  207.  
  208.         bytesWritten = PR_Send(newSock,
  209.                                sendBuf, 
  210.                                bytesToWrite, 
  211.                                0, 
  212.                                PR_INTERVAL_NO_TIMEOUT);
  213.         if (bytesWritten != _server_data)
  214.             if (debug_mode) printf("\tError sending data to client (%d, %d)\n", 
  215.                 bytesWritten, PR_GetOSError());
  216.         else
  217.             if (debug_mode) DPRINTF("\tServer sent %d bytes\n", bytesWritten);
  218.  
  219.         PR_Close(newSock);
  220.         PR_AtomicDecrement(&workerThreadsBusy);
  221.     }
  222. }
  223.  
  224. PRFileDesc *
  225. ServerSetup(void)
  226. {
  227.     PRFileDesc *listenSocket;
  228.     PRNetAddr serverAddr;
  229.     PRThread *WorkerThread;
  230.  
  231.     if ( (listenSocket = PR_NewTCPSocket()) == NULL) {
  232.         if (debug_mode) printf("\tServer error creating listen socket\n");
  233.         else 
  234.         return NULL;
  235.     }
  236.  
  237.     memset(&serverAddr, 0, sizeof(PRNetAddr));
  238.     serverAddr.inet.family = AF_INET;
  239.     serverAddr.inet.port = PR_htons(PORT);
  240.     serverAddr.inet.ip = PR_htonl(INADDR_ANY);
  241.  
  242.     if ( PR_Bind(listenSocket, &serverAddr) == PR_FAILURE) {
  243.         if (debug_mode) printf("\tServer error binding to server address: OS error %d\n",
  244.                 PR_GetOSError());
  245.         else failed_already=1;
  246.         PR_Close(listenSocket);
  247.         return NULL;
  248.     }
  249.  
  250.     if ( PR_Listen(listenSocket, 128) == PR_FAILURE) {
  251.         if (debug_mode) printf("\tServer error listening to server socket\n");
  252.         else failed_already=1;
  253.         PR_Close(listenSocket);
  254.  
  255.         return NULL;
  256.     }
  257.  
  258.     /* Create Clients */
  259.     workerThreads = 0;
  260.     workerThreadsBusy = 0;
  261.  
  262.     workerThreadsLock = PR_NewLock();
  263.  
  264.     WorkerThread = PR_CreateThread(
  265.                       PR_SYSTEM_THREAD,
  266.                       WorkerThreadFunc,
  267.                       listenSocket,
  268.                       PR_PRIORITY_NORMAL,
  269.                       ServerScope,
  270.                       PR_UNJOINABLE_THREAD,
  271.                       STACKSIZE);
  272.  
  273.     if (!WorkerThread) {
  274.         if (debug_mode) printf("error creating working thread\n");
  275.         PR_Close(listenSocket);
  276.         return NULL;
  277.     }
  278.     PR_AtomicIncrement(&workerThreads);
  279.     if (debug_mode) DPRINTF("\tServer created primordial worker thread\n");
  280.  
  281.     return listenSocket;
  282. }
  283.  
  284. /* The main server loop */
  285. void
  286. ServerThreadFunc(void *unused)
  287. {
  288.     PRFileDesc *listenSocket;
  289.  
  290.     /* Do setup */
  291.     listenSocket = ServerSetup();
  292.  
  293.     if (!listenSocket) {
  294.         SetServerState(SERVER, SERVER_STATE_DEAD);
  295.     } else {
  296.  
  297.         if (debug_mode) DPRINTF("\tServer up\n");
  298.  
  299.         /* Tell clients they can start now. */
  300.         SetServerState(SERVER, SERVER_STATE_READY);
  301.  
  302.         /* Now wait for server death signal */
  303.         WaitServerState(SERVER, SERVER_STATE_DYING);
  304.  
  305.         /* Cleanup */
  306.         SetServerState(SERVER, SERVER_STATE_DEAD);
  307.     }
  308. }
  309.  
  310. /* --- Client Functions ------------------------------------------- */
  311.  
  312. PRInt32 numRequests;
  313. PRInt32 numClients;
  314. PRMonitor *clientMonitor;
  315.  
  316. void
  317. ClientThreadFunc(void *unused)
  318. {
  319.     PRNetAddr serverAddr;
  320.     PRFileDesc *clientSocket;
  321.     char *sendBuf;
  322.     char *recvBuf;
  323.     PRInt32 rv;
  324.     PRInt32 bytesNeeded;
  325.  
  326.     sendBuf = (char *)PR_MALLOC(_client_data * sizeof(char));
  327.     if (!sendBuf)
  328.         if (debug_mode) printf("\tClient could not malloc space!?\n");
  329.     recvBuf = (char *)PR_MALLOC(_server_data * sizeof(char));
  330.     if (!recvBuf)
  331.         if (debug_mode) printf("\tClient could not malloc space!?\n");
  332.  
  333.     memset(&serverAddr, 0, sizeof(PRNetAddr));
  334.     serverAddr.inet.family = AF_INET;
  335.     serverAddr.inet.port = PR_htons(PORT);
  336.     serverAddr.inet.ip = PR_htonl(INADDR_LOOPBACK);
  337.  
  338.     while(numRequests > 0) {
  339.  
  340.         if ( (numRequests % 10) == 0 )
  341.             if (debug_mode) printf(".");
  342.         if (debug_mode) DPRINTF("\tClient starting request %d\n", numRequests);
  343.  
  344.         clientSocket = PR_NewTCPSocket();
  345.         if (!clientSocket) {
  346.             if (debug_mode) printf("Client error creating socket: OS error %d\n",
  347.             PR_GetOSError());
  348.             continue;
  349.         }
  350.  
  351.         if (debug_mode) DPRINTF("\tClient connecting\n");
  352.  
  353.         rv = PR_Connect(clientSocket, 
  354.                         &serverAddr,
  355.                         PR_INTERVAL_NO_TIMEOUT);
  356.         if (!clientSocket) {
  357.             if (debug_mode) printf("\tClient error connecting\n");
  358.             continue;
  359.         }
  360.  
  361.         if (debug_mode) DPRINTF("\tClient connected\n");
  362.  
  363.         rv = PR_Send(clientSocket, 
  364.                      sendBuf, 
  365.                      _client_data, 
  366.                      0, 
  367.                      PR_INTERVAL_NO_TIMEOUT);
  368.         if (rv != _client_data) {
  369.             if (debug_mode) printf("Client error sending data (%d)\n", rv);
  370.             PR_Close(clientSocket);
  371.             continue;
  372.         }
  373.  
  374.         if (debug_mode) DPRINTF("\tClient sent %d bytes\n", rv);
  375.  
  376.         bytesNeeded = _server_data;
  377.         while(bytesNeeded) {
  378.             rv = PR_Recv(clientSocket, 
  379.                          recvBuf, 
  380.                          bytesNeeded, 
  381.                          0, 
  382.                          PR_INTERVAL_NO_TIMEOUT);
  383.             if (rv <= 0) {
  384.                 if (debug_mode) printf("Client error receiving data (%d) (%d/%d)\n", 
  385.                     rv, (_server_data - bytesNeeded), _server_data);
  386.                 break;
  387.             }
  388.             if (debug_mode) DPRINTF("\tClient received %d bytes; need %d more\n", rv, bytesNeeded - rv);
  389.             bytesNeeded -= rv;
  390.         }
  391.  
  392.         PR_Close(clientSocket);
  393.  
  394.         PR_AtomicDecrement(&numRequests);
  395.     }
  396.  
  397.     PR_EnterMonitor(clientMonitor);
  398.     --numClients;
  399.     PR_Notify(clientMonitor);
  400.     PR_ExitMonitor(clientMonitor);
  401.  
  402.     PR_DELETE(sendBuf);
  403.     PR_DELETE(recvBuf);
  404. }
  405.  
  406. void
  407. RunClients(void)
  408. {
  409.     PRInt32 index;
  410.  
  411.     numRequests = _iterations;
  412.     numClients = _clients;
  413.     clientMonitor = PR_NewMonitor();
  414.  
  415.     for (index=0; index<_clients; index++) {
  416.         PRThread *clientThread;
  417.  
  418.   
  419.         clientThread = PR_CreateThread(
  420.                           PR_USER_THREAD,
  421.                           ClientThreadFunc,
  422.                           NULL,
  423.                           PR_PRIORITY_NORMAL,
  424.                           ClientScope,
  425.                           PR_UNJOINABLE_THREAD,
  426.                           STACKSIZE);
  427.  
  428.         if (!clientThread) {
  429.             if (debug_mode) printf("\terror creating client thread %d\n", index);
  430.         } else
  431.             if (debug_mode) DPRINTF("\tMain created client %d/%d\n", index+1, _clients);
  432.  
  433.     }
  434.  
  435.     PR_EnterMonitor(clientMonitor);
  436.     while(numClients)
  437.         PR_Wait(clientMonitor, PR_INTERVAL_NO_TIMEOUT);
  438.     PR_ExitMonitor(clientMonitor);
  439. }
  440.  
  441. /* --- Main Function ---------------------------------------------- */
  442.  
  443. static
  444. void do_work()
  445. {
  446.     PRThread *ServerThread;
  447.     PRInt32 state;
  448.  
  449.     SetServerState(MAIN, SERVER_STATE_STARTUP);
  450.     ServerThread = PR_CreateThread(
  451.                       PR_USER_THREAD,
  452.                       ServerThreadFunc,
  453.                       NULL,
  454.                       PR_PRIORITY_NORMAL,
  455.                       ServerScope,
  456.                       PR_JOINABLE_THREAD,
  457.                       STACKSIZE);
  458.     if (!ServerThread) {
  459.         if (debug_mode) printf("error creating main server thread\n");
  460.         return;
  461.     }
  462.  
  463.     /* Wait for server to be ready */
  464.     state = WaitServerState(MAIN, SERVER_STATE_READY|SERVER_STATE_DEAD);
  465.  
  466.     if (!(state & SERVER_STATE_DEAD)) {
  467.         /* Run Test Clients */
  468.         RunClients();
  469.  
  470.         /* Send death signal to server */
  471.         SetServerState(MAIN, SERVER_STATE_DYING);
  472.     }
  473.  
  474.     PR_JoinThread(ServerThread);
  475. }
  476.  
  477.  
  478. static void do_workUK(void)
  479. {
  480.     ServerScope = PR_LOCAL_THREAD;
  481.     ClientScope = PR_GLOBAL_THREAD;
  482.     do_work();
  483. }
  484.  
  485.  
  486.  
  487. static void Measure(void (*func)(void), const char *msg)
  488. {
  489.     PRIntervalTime start, stop;
  490.     double d;
  491.  
  492.     start = PR_IntervalNow();
  493.     (*func)();
  494.     stop = PR_IntervalNow();
  495.  
  496.     d = (double)PR_IntervalToMicroseconds(stop - start);
  497.  
  498.     if (debug_mode) printf("\n%40s: %6.2f usec\n", msg, d / _iterations);
  499. }
  500.  
  501.  
  502. main(int argc, char **argv)
  503. {
  504.     /* The command line argument: -d is used to determine if the test is being run
  505.     in debug mode. The regress tool requires only one line output:PASS or FAIL.
  506.     All of the printfs associated with this test has been handled with a if (debug_mode)
  507.     test.
  508.     Usage: test_name -d
  509.     */
  510.     PLOptStatus os;
  511.     PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
  512.     while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
  513.     {
  514.         if (PL_OPT_BAD == os) continue;
  515.         switch (opt->option)
  516.         {
  517.         case 'd':  /* debug mode */
  518.             debug_mode = 1;
  519.             break;
  520.          default:
  521.             break;
  522.         }
  523.     }
  524.     PL_DestroyOptState(opt);
  525.  
  526.  /* main test */
  527.     if (debug_mode) {
  528.         printf("Enter number of iterations: \n");
  529.         scanf("%d", &_iterations);
  530.         printf("Enter number of clients   : \n");
  531.         scanf("%d", &_clients);
  532.         printf("Enter size of client data : \n");
  533.         scanf("%d", &_client_data);
  534.         printf("Enter size of server data : \n");
  535.         scanf("%d", &_server_data);
  536.     }
  537.     else {
  538.         _iterations = 7;
  539.         _clients = 7;
  540.         _client_data = 100;
  541.         _server_data = 100;
  542.     }
  543.  
  544.     if (debug_mode) {
  545.         printf("\n\n%d iterations with %d client threads.\n", 
  546.         _iterations, _clients);
  547.         printf("Sending %d bytes of client data and %d bytes of server data\n", 
  548.         _client_data, _server_data);
  549.     }
  550.     PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
  551.     PR_STDIO_INIT();
  552.  
  553.     PR_SetThreadRecycleMode(64);
  554.  
  555.     ServerStateCVLock = PR_NewLock();
  556.     ServerStateCV = PR_NewCondVar(ServerStateCVLock);
  557.  
  558.     Measure(do_workUK, "server loop user/kernel");
  559.  
  560.     PR_Cleanup();
  561.  
  562.     if(failed_already)    
  563.         return 1;
  564.     else
  565.         return 0;
  566. }
  567.