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