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