Bug 449371 Firefox/Thunderbird crashes at exit [@ gdk_display_x11_finalize], p=Brian...
[wine-gecko.git] / nsprpub / pr / tests / servr_kk.c
blob9fbb9b00e6f8da041c5a278614f1bd91d25c7e9f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is the Netscape Portable Runtime (NSPR).
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998-2000
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 /***********************************************************************
40 ** This server simulates a server running in loopback mode.
42 ** The idea is that a single server is created. The server initially creates
43 ** a number of worker threads. Then, with the server running, a number of
44 ** clients are created which start requesting service from the server.
47 ** Modification History:
48 ** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
49 ** The debug mode will print all of the printfs associated with this test.
50 ** The regress mode will be the default mode. Since the regress tool limits
51 ** the output to a one line status:PASS or FAIL,all of the printf statements
52 ** have been handled with an if (debug_mode) statement.
53 ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
54 ** recognize the return code from tha main program.
55 ***********************************************************************/
57 /***********************************************************************
58 ** Includes
59 ***********************************************************************/
60 /* Used to get the command line option */
61 #include "plgetopt.h"
63 #include "nspr.h"
64 #include "pprthred.h"
66 #include <string.h>
68 #define PORT 15004
69 #define THREAD_STACKSIZE 0
71 static int _iterations = 1000;
72 static int _clients = 1;
73 static int _client_data = 250;
74 static int _server_data = (8*1024);
76 static PRThreadScope ServerScope, ClientScope;
78 #define SERVER "Server"
79 #define MAIN "Main"
81 #define SERVER_STATE_STARTUP 0
82 #define SERVER_STATE_READY 1
83 #define SERVER_STATE_DYING 2
84 #define SERVER_STATE_DEAD 4
85 int ServerState;
86 PRLock *ServerStateCVLock;
87 PRCondVar *ServerStateCV;
89 #ifdef DEBUGPRINTS
90 #define DPRINTF printf
91 #else
92 #define DPRINTF
93 #endif
95 PRIntn failed_already=0;
96 PRIntn debug_mode;
97 static void do_work(void);
99 /* --- Server state functions --------------------------------------------- */
100 void
101 SetServerState(char *waiter, PRInt32 state)
103 PR_Lock(ServerStateCVLock);
104 ServerState = state;
105 PR_NotifyCondVar(ServerStateCV);
107 if (debug_mode) DPRINTF("\t%s changed state to %d\n", waiter, state);
109 PR_Unlock(ServerStateCVLock);
113 WaitServerState(char *waiter, PRInt32 state)
115 PRInt32 rv;
117 PR_Lock(ServerStateCVLock);
119 if (debug_mode) DPRINTF("\t%s waiting for state %d\n", waiter, state);
121 while(!(ServerState & state))
122 PR_WaitCondVar(ServerStateCV, PR_INTERVAL_NO_TIMEOUT);
123 rv = ServerState;
125 if (debug_mode) DPRINTF("\t%s resuming from wait for state %d; state now %d\n",
126 waiter, state, ServerState);
127 PR_Unlock(ServerStateCVLock);
129 return rv;
132 /* --- Server Functions ------------------------------------------- */
134 PRLock *workerThreadsLock;
135 PRInt32 workerThreads;
136 PRInt32 workerThreadsBusy;
138 void
139 WorkerThreadFunc(void *_listenSock)
141 PRFileDesc *listenSock = (PRFileDesc *)_listenSock;
142 PRInt32 bytesRead;
143 PRInt32 bytesWritten;
144 char *dataBuf;
145 char *sendBuf;
147 if (debug_mode) DPRINTF("\tServer buffer is %d bytes; %d data, %d netaddrs\n",
148 _client_data+(2*sizeof(PRNetAddr))+32, _client_data, (2*sizeof(PRNetAddr))+32);
149 dataBuf = (char *)PR_MALLOC(_client_data + 2*sizeof(PRNetAddr) + 32);
150 if (!dataBuf)
151 if (debug_mode) printf("\tServer could not malloc space!?\n");
152 sendBuf = (char *)PR_MALLOC(_server_data *sizeof(char));
153 if (!sendBuf)
154 if (debug_mode) printf("\tServer could not malloc space!?\n");
156 if (debug_mode) DPRINTF("\tServer worker thread running\n");
158 while(1) {
159 PRInt32 bytesToRead = _client_data;
160 PRInt32 bytesToWrite = _server_data;
161 PRFileDesc *newSock;
162 PRNetAddr *rAddr;
163 PRInt32 loops = 0;
165 loops++;
167 if (debug_mode) DPRINTF("\tServer thread going into accept\n");
169 bytesRead = PR_AcceptRead(listenSock,
170 &newSock,
171 &rAddr,
172 dataBuf,
173 bytesToRead,
174 PR_INTERVAL_NO_TIMEOUT);
176 if (bytesRead < 0) {
177 if (debug_mode) printf("\tServer error in accept (%d)\n", bytesRead);
178 continue;
181 if (debug_mode) DPRINTF("\tServer accepted connection (%d bytes)\n", bytesRead);
183 PR_AtomicIncrement(&workerThreadsBusy);
184 if (workerThreadsBusy == workerThreads) {
186 PR_Lock(workerThreadsLock);
187 if (workerThreadsBusy == workerThreads) {
188 PRThread *WorkerThread;
190 WorkerThread = PR_CreateThread(
191 PR_SYSTEM_THREAD,
192 WorkerThreadFunc,
193 listenSock,
194 PR_PRIORITY_NORMAL,
195 ServerScope,
196 PR_UNJOINABLE_THREAD,
197 THREAD_STACKSIZE);
199 if (!WorkerThread) {
200 if (debug_mode) printf("Error creating client thread %d\n", workerThreads);
201 } else {
202 PR_AtomicIncrement(&workerThreads);
203 if (debug_mode) DPRINTF("\tServer creates worker (%d)\n", workerThreads);
206 PR_Unlock(workerThreadsLock);
209 bytesToRead -= bytesRead;
210 while (bytesToRead) {
211 bytesRead = PR_Recv(newSock,
212 dataBuf,
213 bytesToRead,
215 PR_INTERVAL_NO_TIMEOUT);
216 if (bytesRead < 0) {
217 if (debug_mode) printf("\tServer error receiving data (%d)\n", bytesRead);
218 continue;
220 if (debug_mode) DPRINTF("\tServer received %d bytes\n", bytesRead);
223 bytesWritten = PR_Send(newSock,
224 sendBuf,
225 bytesToWrite,
227 PR_INTERVAL_NO_TIMEOUT);
228 if (bytesWritten != _server_data) {
229 if (debug_mode) printf("\tError sending data to client (%d, %d)\n",
230 bytesWritten, PR_GetOSError());
231 } else {
232 if (debug_mode) DPRINTF("\tServer sent %d bytes\n", bytesWritten);
235 PR_Close(newSock);
236 PR_AtomicDecrement(&workerThreadsBusy);
240 PRFileDesc *
241 ServerSetup(void)
243 PRFileDesc *listenSocket;
244 PRSocketOptionData sockOpt;
245 PRNetAddr serverAddr;
246 PRThread *WorkerThread;
248 if ( (listenSocket = PR_NewTCPSocket()) == NULL) {
249 if (debug_mode) printf("\tServer error creating listen socket\n");
250 else failed_already=1;
251 return NULL;
254 sockOpt.option = PR_SockOpt_Reuseaddr;
255 sockOpt.value.reuse_addr = PR_TRUE;
256 if ( PR_SetSocketOption(listenSocket, &sockOpt) == PR_FAILURE) {
257 if (debug_mode) printf("\tServer error setting socket option: OS error %d\n",
258 PR_GetOSError());
259 else failed_already=1;
260 PR_Close(listenSocket);
261 return NULL;
264 memset(&serverAddr, 0, sizeof(PRNetAddr));
265 serverAddr.inet.family = PR_AF_INET;
266 serverAddr.inet.port = PR_htons(PORT);
267 serverAddr.inet.ip = PR_htonl(PR_INADDR_ANY);
269 if ( PR_Bind(listenSocket, &serverAddr) == PR_FAILURE) {
270 if (debug_mode) printf("\tServer error binding to server address: OS error %d\n",
271 PR_GetOSError());
272 else failed_already=1;
273 PR_Close(listenSocket);
274 return NULL;
277 if ( PR_Listen(listenSocket, 128) == PR_FAILURE) {
278 if (debug_mode) printf("\tServer error listening to server socket\n");
279 else failed_already=1;
280 PR_Close(listenSocket);
282 return NULL;
285 /* Create Clients */
286 workerThreads = 0;
287 workerThreadsBusy = 0;
289 workerThreadsLock = PR_NewLock();
291 WorkerThread = PR_CreateThread(
292 PR_SYSTEM_THREAD,
293 WorkerThreadFunc,
294 listenSocket,
295 PR_PRIORITY_NORMAL,
296 ServerScope,
297 PR_UNJOINABLE_THREAD,
298 THREAD_STACKSIZE);
300 if (!WorkerThread) {
301 if (debug_mode) printf("error creating working thread\n");
302 PR_Close(listenSocket);
303 return NULL;
305 PR_AtomicIncrement(&workerThreads);
306 if (debug_mode) DPRINTF("\tServer created primordial worker thread\n");
308 return listenSocket;
311 /* The main server loop */
312 void
313 ServerThreadFunc(void *unused)
315 PRFileDesc *listenSocket;
317 /* Do setup */
318 listenSocket = ServerSetup();
320 if (!listenSocket) {
321 SetServerState(SERVER, SERVER_STATE_DEAD);
322 } else {
324 if (debug_mode) DPRINTF("\tServer up\n");
326 /* Tell clients they can start now. */
327 SetServerState(SERVER, SERVER_STATE_READY);
329 /* Now wait for server death signal */
330 WaitServerState(SERVER, SERVER_STATE_DYING);
332 /* Cleanup */
333 SetServerState(SERVER, SERVER_STATE_DEAD);
337 /* --- Client Functions ------------------------------------------- */
339 PRInt32 numRequests;
340 PRInt32 numClients;
341 PRMonitor *clientMonitor;
343 void
344 ClientThreadFunc(void *unused)
346 PRNetAddr serverAddr;
347 PRFileDesc *clientSocket;
348 char *sendBuf;
349 char *recvBuf;
350 PRInt32 rv;
351 PRInt32 bytesNeeded;
353 sendBuf = (char *)PR_MALLOC(_client_data * sizeof(char));
354 if (!sendBuf)
355 if (debug_mode) printf("\tClient could not malloc space!?\n");
356 recvBuf = (char *)PR_MALLOC(_server_data * sizeof(char));
357 if (!recvBuf)
358 if (debug_mode) printf("\tClient could not malloc space!?\n");
360 memset(&serverAddr, 0, sizeof(PRNetAddr));
361 serverAddr.inet.family = PR_AF_INET;
362 serverAddr.inet.port = PR_htons(PORT);
363 serverAddr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
365 while(numRequests > 0) {
367 if ( (numRequests % 10) == 0 )
368 if (debug_mode) printf(".");
369 if (debug_mode) DPRINTF("\tClient starting request %d\n", numRequests);
371 clientSocket = PR_NewTCPSocket();
372 if (!clientSocket) {
373 if (debug_mode) printf("Client error creating socket: OS error %d\n",
374 PR_GetOSError());
375 continue;
378 if (debug_mode) DPRINTF("\tClient connecting\n");
380 rv = PR_Connect(clientSocket,
381 &serverAddr,
382 PR_INTERVAL_NO_TIMEOUT);
383 if (!clientSocket) {
384 if (debug_mode) printf("\tClient error connecting\n");
385 continue;
388 if (debug_mode) DPRINTF("\tClient connected\n");
390 rv = PR_Send(clientSocket,
391 sendBuf,
392 _client_data,
394 PR_INTERVAL_NO_TIMEOUT);
395 if (rv != _client_data) {
396 if (debug_mode) printf("Client error sending data (%d)\n", rv);
397 PR_Close(clientSocket);
398 continue;
401 if (debug_mode) DPRINTF("\tClient sent %d bytes\n", rv);
403 bytesNeeded = _server_data;
404 while(bytesNeeded) {
405 rv = PR_Recv(clientSocket,
406 recvBuf,
407 bytesNeeded,
409 PR_INTERVAL_NO_TIMEOUT);
410 if (rv <= 0) {
411 if (debug_mode) printf("Client error receiving data (%d) (%d/%d)\n",
412 rv, (_server_data - bytesNeeded), _server_data);
413 break;
415 if (debug_mode) DPRINTF("\tClient received %d bytes; need %d more\n", rv, bytesNeeded - rv);
416 bytesNeeded -= rv;
419 PR_Close(clientSocket);
421 PR_AtomicDecrement(&numRequests);
424 PR_EnterMonitor(clientMonitor);
425 --numClients;
426 PR_Notify(clientMonitor);
427 PR_ExitMonitor(clientMonitor);
429 PR_DELETE(sendBuf);
430 PR_DELETE(recvBuf);
433 void
434 RunClients(void)
436 PRInt32 index;
438 numRequests = _iterations;
439 numClients = _clients;
440 clientMonitor = PR_NewMonitor();
442 for (index=0; index<_clients; index++) {
443 PRThread *clientThread;
446 clientThread = PR_CreateThread(
447 PR_USER_THREAD,
448 ClientThreadFunc,
449 NULL,
450 PR_PRIORITY_NORMAL,
451 ClientScope,
452 PR_UNJOINABLE_THREAD,
453 THREAD_STACKSIZE);
455 if (!clientThread) {
456 if (debug_mode) printf("\terror creating client thread %d\n", index);
457 } else
458 if (debug_mode) DPRINTF("\tMain created client %d/%d\n", index+1, _clients);
462 PR_EnterMonitor(clientMonitor);
463 while(numClients)
464 PR_Wait(clientMonitor, PR_INTERVAL_NO_TIMEOUT);
465 PR_ExitMonitor(clientMonitor);
468 /* --- Main Function ---------------------------------------------- */
470 static
471 void do_work()
473 PRThread *ServerThread;
474 PRInt32 state;
476 SetServerState(MAIN, SERVER_STATE_STARTUP);
477 ServerThread = PR_CreateThread(
478 PR_USER_THREAD,
479 ServerThreadFunc,
480 NULL,
481 PR_PRIORITY_NORMAL,
482 ServerScope,
483 PR_JOINABLE_THREAD,
484 THREAD_STACKSIZE);
485 if (!ServerThread) {
486 if (debug_mode) printf("error creating main server thread\n");
487 return;
490 /* Wait for server to be ready */
491 state = WaitServerState(MAIN, SERVER_STATE_READY|SERVER_STATE_DEAD);
493 if (!(state & SERVER_STATE_DEAD)) {
494 /* Run Test Clients */
495 RunClients();
497 /* Send death signal to server */
498 SetServerState(MAIN, SERVER_STATE_DYING);
501 PR_JoinThread(ServerThread);
504 static void do_workUU(void)
506 ServerScope = PR_LOCAL_THREAD;
507 ClientScope = PR_LOCAL_THREAD;
508 do_work();
511 static void do_workUK(void)
513 ServerScope = PR_LOCAL_THREAD;
514 ClientScope = PR_GLOBAL_THREAD;
515 do_work();
518 static void do_workKU(void)
520 ServerScope = PR_GLOBAL_THREAD;
521 ClientScope = PR_LOCAL_THREAD;
522 do_work();
525 static void do_workKK(void)
527 ServerScope = PR_GLOBAL_THREAD;
528 ClientScope = PR_GLOBAL_THREAD;
529 do_work();
533 static void Measure(void (*func)(void), const char *msg)
535 PRIntervalTime start, stop;
536 double d;
538 start = PR_IntervalNow();
539 (*func)();
540 stop = PR_IntervalNow();
542 d = (double)PR_IntervalToMicroseconds(stop - start);
544 if (debug_mode) printf("\n%40s: %6.2f usec\n", msg, d / _iterations);
548 int main(int argc, char **argv)
550 /* The command line argument: -d is used to determine if the test is being run
551 in debug mode. The regress tool requires only one line output:PASS or FAIL.
552 All of the printfs associated with this test has been handled with a if (debug_mode)
553 test.
554 Usage: test_name -d
556 PLOptStatus os;
557 PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
558 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
560 if (PL_OPT_BAD == os) continue;
561 switch (opt->option)
563 case 'd': /* debug mode */
564 debug_mode = 1;
565 break;
566 default:
567 break;
570 PL_DestroyOptState(opt);
572 /* main test */
573 if (debug_mode) {
574 printf("Enter number of iterations: \n");
575 scanf("%d", &_iterations);
576 printf("Enter number of clients : \n");
577 scanf("%d", &_clients);
578 printf("Enter size of client data : \n");
579 scanf("%d", &_client_data);
580 printf("Enter size of server data : \n");
581 scanf("%d", &_server_data);
583 else {
584 _iterations = 7;
585 _clients = 7;
586 _client_data = 100;
587 _server_data = 100;
590 if (debug_mode) {
591 printf("\n\n%d iterations with %d client threads.\n",
592 _iterations, _clients);
593 printf("Sending %d bytes of client data and %d bytes of server data\n",
594 _client_data, _server_data);
596 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
597 PR_STDIO_INIT();
599 PR_SetThreadRecycleMode(64);
601 ServerStateCVLock = PR_NewLock();
602 ServerStateCV = PR_NewCondVar(ServerStateCVLock);
605 Measure(do_workKK, "server loop kernel/kernel");
607 PR_Cleanup();
609 if(failed_already)
610 return 1;
611 else
612 return 0;