VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/nsprpub/pr/tests/server_test.c@ 1

Last change on this file since 1 was 1, checked in by vboxsync, 55 years ago

import

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette