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.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | /*********************************************************************** |
michael@0 | 7 | ** |
michael@0 | 8 | ** Name: thrpool.c |
michael@0 | 9 | ** |
michael@0 | 10 | ** Description: Test threadpool functionality. |
michael@0 | 11 | ** |
michael@0 | 12 | ** Modification History: |
michael@0 | 13 | */ |
michael@0 | 14 | #include "primpl.h" |
michael@0 | 15 | |
michael@0 | 16 | #include "plgetopt.h" |
michael@0 | 17 | |
michael@0 | 18 | #include <stdio.h> |
michael@0 | 19 | #include <string.h> |
michael@0 | 20 | #include <errno.h> |
michael@0 | 21 | #ifdef XP_UNIX |
michael@0 | 22 | #include <sys/mman.h> |
michael@0 | 23 | #endif |
michael@0 | 24 | #if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) |
michael@0 | 25 | #include <pthread.h> |
michael@0 | 26 | #endif |
michael@0 | 27 | |
michael@0 | 28 | /* for getcwd */ |
michael@0 | 29 | #if defined(XP_UNIX) || defined (XP_OS2) || defined(XP_BEOS) |
michael@0 | 30 | #include <unistd.h> |
michael@0 | 31 | #elif defined(XP_PC) |
michael@0 | 32 | #include <direct.h> |
michael@0 | 33 | #endif |
michael@0 | 34 | |
michael@0 | 35 | #ifdef WIN32 |
michael@0 | 36 | #include <process.h> |
michael@0 | 37 | #endif |
michael@0 | 38 | |
michael@0 | 39 | static int _debug_on = 0; |
michael@0 | 40 | static char *program_name = NULL; |
michael@0 | 41 | static void serve_client_write(void *arg); |
michael@0 | 42 | |
michael@0 | 43 | #include "obsolete/prsem.h" |
michael@0 | 44 | |
michael@0 | 45 | #ifdef XP_PC |
michael@0 | 46 | #define mode_t int |
michael@0 | 47 | #endif |
michael@0 | 48 | |
michael@0 | 49 | #define DPRINTF(arg) if (_debug_on) printf arg |
michael@0 | 50 | |
michael@0 | 51 | |
michael@0 | 52 | #define BUF_DATA_SIZE (2 * 1024) |
michael@0 | 53 | #define TCP_MESG_SIZE 1024 |
michael@0 | 54 | #define NUM_TCP_CLIENTS 10 /* for a listen queue depth of 5 */ |
michael@0 | 55 | |
michael@0 | 56 | |
michael@0 | 57 | #define NUM_TCP_CONNECTIONS_PER_CLIENT 10 |
michael@0 | 58 | #define NUM_TCP_MESGS_PER_CONNECTION 10 |
michael@0 | 59 | #define TCP_SERVER_PORT 10000 |
michael@0 | 60 | #define SERVER_MAX_BIND_COUNT 100 |
michael@0 | 61 | |
michael@0 | 62 | #ifdef WINCE |
michael@0 | 63 | char *getcwd(char *buf, size_t size) |
michael@0 | 64 | { |
michael@0 | 65 | wchar_t wpath[MAX_PATH]; |
michael@0 | 66 | _wgetcwd(wpath, MAX_PATH); |
michael@0 | 67 | WideCharToMultiByte(CP_ACP, 0, wpath, -1, buf, size, 0, 0); |
michael@0 | 68 | } |
michael@0 | 69 | |
michael@0 | 70 | #define perror(s) |
michael@0 | 71 | #endif |
michael@0 | 72 | |
michael@0 | 73 | static PRInt32 num_tcp_clients = NUM_TCP_CLIENTS; |
michael@0 | 74 | static PRInt32 num_tcp_connections_per_client = NUM_TCP_CONNECTIONS_PER_CLIENT; |
michael@0 | 75 | static PRInt32 tcp_mesg_size = TCP_MESG_SIZE; |
michael@0 | 76 | static PRInt32 num_tcp_mesgs_per_connection = NUM_TCP_MESGS_PER_CONNECTION; |
michael@0 | 77 | static void TCP_Server_Accept(void *arg); |
michael@0 | 78 | |
michael@0 | 79 | |
michael@0 | 80 | int failed_already=0; |
michael@0 | 81 | typedef struct buffer { |
michael@0 | 82 | char data[BUF_DATA_SIZE]; |
michael@0 | 83 | } buffer; |
michael@0 | 84 | |
michael@0 | 85 | |
michael@0 | 86 | typedef struct Server_Param { |
michael@0 | 87 | PRJobIoDesc iod; /* socket to read from/write to */ |
michael@0 | 88 | PRInt32 datalen; /* bytes of data transfered in each read/write */ |
michael@0 | 89 | PRNetAddr netaddr; |
michael@0 | 90 | PRMonitor *exit_mon; /* monitor to signal on exit */ |
michael@0 | 91 | PRInt32 *job_counterp; /* counter to decrement, before exit */ |
michael@0 | 92 | PRInt32 conn_counter; /* counter to decrement, before exit */ |
michael@0 | 93 | PRThreadPool *tp; |
michael@0 | 94 | } Server_Param; |
michael@0 | 95 | |
michael@0 | 96 | typedef struct Serve_Client_Param { |
michael@0 | 97 | PRJobIoDesc iod; /* socket to read from/write to */ |
michael@0 | 98 | PRInt32 datalen; /* bytes of data transfered in each read/write */ |
michael@0 | 99 | PRMonitor *exit_mon; /* monitor to signal on exit */ |
michael@0 | 100 | PRInt32 *job_counterp; /* counter to decrement, before exit */ |
michael@0 | 101 | PRThreadPool *tp; |
michael@0 | 102 | } Serve_Client_Param; |
michael@0 | 103 | |
michael@0 | 104 | typedef struct Session { |
michael@0 | 105 | PRJobIoDesc iod; /* socket to read from/write to */ |
michael@0 | 106 | buffer *in_buf; |
michael@0 | 107 | PRInt32 bytes; |
michael@0 | 108 | PRInt32 msg_num; |
michael@0 | 109 | PRInt32 bytes_read; |
michael@0 | 110 | PRMonitor *exit_mon; /* monitor to signal on exit */ |
michael@0 | 111 | PRInt32 *job_counterp; /* counter to decrement, before exit */ |
michael@0 | 112 | PRThreadPool *tp; |
michael@0 | 113 | } Session; |
michael@0 | 114 | |
michael@0 | 115 | static void |
michael@0 | 116 | serve_client_read(void *arg) |
michael@0 | 117 | { |
michael@0 | 118 | Session *sp = (Session *) arg; |
michael@0 | 119 | int rem; |
michael@0 | 120 | int bytes; |
michael@0 | 121 | int offset; |
michael@0 | 122 | PRFileDesc *sockfd; |
michael@0 | 123 | char *buf; |
michael@0 | 124 | PRJob *jobp; |
michael@0 | 125 | |
michael@0 | 126 | PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT; |
michael@0 | 127 | |
michael@0 | 128 | sockfd = sp->iod.socket; |
michael@0 | 129 | buf = sp->in_buf->data; |
michael@0 | 130 | |
michael@0 | 131 | PR_ASSERT(sp->msg_num < num_tcp_mesgs_per_connection); |
michael@0 | 132 | PR_ASSERT(sp->bytes_read < sp->bytes); |
michael@0 | 133 | |
michael@0 | 134 | offset = sp->bytes_read; |
michael@0 | 135 | rem = sp->bytes - offset; |
michael@0 | 136 | bytes = PR_Recv(sockfd, buf + offset, rem, 0, timeout); |
michael@0 | 137 | if (bytes < 0) { |
michael@0 | 138 | return; |
michael@0 | 139 | } |
michael@0 | 140 | sp->bytes_read += bytes; |
michael@0 | 141 | sp->iod.timeout = PR_SecondsToInterval(60); |
michael@0 | 142 | if (sp->bytes_read < sp->bytes) { |
michael@0 | 143 | jobp = PR_QueueJob_Read(sp->tp, &sp->iod, serve_client_read, sp, |
michael@0 | 144 | PR_FALSE); |
michael@0 | 145 | PR_ASSERT(NULL != jobp); |
michael@0 | 146 | return; |
michael@0 | 147 | } |
michael@0 | 148 | PR_ASSERT(sp->bytes_read == sp->bytes); |
michael@0 | 149 | DPRINTF(("serve_client: read complete, msg(%d) \n", sp->msg_num)); |
michael@0 | 150 | |
michael@0 | 151 | sp->iod.timeout = PR_SecondsToInterval(60); |
michael@0 | 152 | jobp = PR_QueueJob_Write(sp->tp, &sp->iod, serve_client_write, sp, |
michael@0 | 153 | PR_FALSE); |
michael@0 | 154 | PR_ASSERT(NULL != jobp); |
michael@0 | 155 | |
michael@0 | 156 | return; |
michael@0 | 157 | } |
michael@0 | 158 | |
michael@0 | 159 | static void |
michael@0 | 160 | serve_client_write(void *arg) |
michael@0 | 161 | { |
michael@0 | 162 | Session *sp = (Session *) arg; |
michael@0 | 163 | int bytes; |
michael@0 | 164 | PRFileDesc *sockfd; |
michael@0 | 165 | char *buf; |
michael@0 | 166 | PRJob *jobp; |
michael@0 | 167 | |
michael@0 | 168 | sockfd = sp->iod.socket; |
michael@0 | 169 | buf = sp->in_buf->data; |
michael@0 | 170 | |
michael@0 | 171 | PR_ASSERT(sp->msg_num < num_tcp_mesgs_per_connection); |
michael@0 | 172 | |
michael@0 | 173 | bytes = PR_Send(sockfd, buf, sp->bytes, 0, PR_INTERVAL_NO_TIMEOUT); |
michael@0 | 174 | PR_ASSERT(bytes == sp->bytes); |
michael@0 | 175 | |
michael@0 | 176 | if (bytes < 0) { |
michael@0 | 177 | return; |
michael@0 | 178 | } |
michael@0 | 179 | DPRINTF(("serve_client: write complete, msg(%d) \n", sp->msg_num)); |
michael@0 | 180 | sp->msg_num++; |
michael@0 | 181 | if (sp->msg_num < num_tcp_mesgs_per_connection) { |
michael@0 | 182 | sp->bytes_read = 0; |
michael@0 | 183 | sp->iod.timeout = PR_SecondsToInterval(60); |
michael@0 | 184 | jobp = PR_QueueJob_Read(sp->tp, &sp->iod, serve_client_read, sp, |
michael@0 | 185 | PR_FALSE); |
michael@0 | 186 | PR_ASSERT(NULL != jobp); |
michael@0 | 187 | return; |
michael@0 | 188 | } |
michael@0 | 189 | |
michael@0 | 190 | DPRINTF(("serve_client: read/write complete, msg(%d) \n", sp->msg_num)); |
michael@0 | 191 | if (PR_Shutdown(sockfd, PR_SHUTDOWN_BOTH) < 0) { |
michael@0 | 192 | fprintf(stderr,"%s: ERROR - PR_Shutdown\n", program_name); |
michael@0 | 193 | } |
michael@0 | 194 | |
michael@0 | 195 | PR_Close(sockfd); |
michael@0 | 196 | PR_EnterMonitor(sp->exit_mon); |
michael@0 | 197 | --(*sp->job_counterp); |
michael@0 | 198 | PR_Notify(sp->exit_mon); |
michael@0 | 199 | PR_ExitMonitor(sp->exit_mon); |
michael@0 | 200 | |
michael@0 | 201 | PR_DELETE(sp->in_buf); |
michael@0 | 202 | PR_DELETE(sp); |
michael@0 | 203 | |
michael@0 | 204 | return; |
michael@0 | 205 | } |
michael@0 | 206 | |
michael@0 | 207 | /* |
michael@0 | 208 | * Serve_Client |
michael@0 | 209 | * Thread, started by the server, for serving a client connection. |
michael@0 | 210 | * Reads data from socket and writes it back, unmodified, and |
michael@0 | 211 | * closes the socket |
michael@0 | 212 | */ |
michael@0 | 213 | static void PR_CALLBACK |
michael@0 | 214 | Serve_Client(void *arg) |
michael@0 | 215 | { |
michael@0 | 216 | Serve_Client_Param *scp = (Serve_Client_Param *) arg; |
michael@0 | 217 | buffer *in_buf; |
michael@0 | 218 | Session *sp; |
michael@0 | 219 | PRJob *jobp; |
michael@0 | 220 | |
michael@0 | 221 | sp = PR_NEW(Session); |
michael@0 | 222 | sp->iod = scp->iod; |
michael@0 | 223 | |
michael@0 | 224 | in_buf = PR_NEW(buffer); |
michael@0 | 225 | if (in_buf == NULL) { |
michael@0 | 226 | fprintf(stderr,"%s: failed to alloc buffer struct\n",program_name); |
michael@0 | 227 | failed_already=1; |
michael@0 | 228 | return; |
michael@0 | 229 | } |
michael@0 | 230 | |
michael@0 | 231 | sp->in_buf = in_buf; |
michael@0 | 232 | sp->bytes = scp->datalen; |
michael@0 | 233 | sp->msg_num = 0; |
michael@0 | 234 | sp->bytes_read = 0; |
michael@0 | 235 | sp->tp = scp->tp; |
michael@0 | 236 | sp->exit_mon = scp->exit_mon; |
michael@0 | 237 | sp->job_counterp = scp->job_counterp; |
michael@0 | 238 | |
michael@0 | 239 | sp->iod.timeout = PR_SecondsToInterval(60); |
michael@0 | 240 | jobp = PR_QueueJob_Read(sp->tp, &sp->iod, serve_client_read, sp, |
michael@0 | 241 | PR_FALSE); |
michael@0 | 242 | PR_ASSERT(NULL != jobp); |
michael@0 | 243 | PR_DELETE(scp); |
michael@0 | 244 | } |
michael@0 | 245 | |
michael@0 | 246 | static void |
michael@0 | 247 | print_stats(void *arg) |
michael@0 | 248 | { |
michael@0 | 249 | Server_Param *sp = (Server_Param *) arg; |
michael@0 | 250 | PRThreadPool *tp = sp->tp; |
michael@0 | 251 | PRInt32 counter; |
michael@0 | 252 | PRJob *jobp; |
michael@0 | 253 | |
michael@0 | 254 | PR_EnterMonitor(sp->exit_mon); |
michael@0 | 255 | counter = (*sp->job_counterp); |
michael@0 | 256 | PR_ExitMonitor(sp->exit_mon); |
michael@0 | 257 | |
michael@0 | 258 | printf("PRINT_STATS: #client connections = %d\n",counter); |
michael@0 | 259 | |
michael@0 | 260 | |
michael@0 | 261 | jobp = PR_QueueJob_Timer(tp, PR_MillisecondsToInterval(500), |
michael@0 | 262 | print_stats, sp, PR_FALSE); |
michael@0 | 263 | |
michael@0 | 264 | PR_ASSERT(NULL != jobp); |
michael@0 | 265 | } |
michael@0 | 266 | |
michael@0 | 267 | static int job_counter = 0; |
michael@0 | 268 | /* |
michael@0 | 269 | * TCP Server |
michael@0 | 270 | * Server binds an address to a socket, starts a client process and |
michael@0 | 271 | * listens for incoming connections. |
michael@0 | 272 | * Each client connects to the server and sends a chunk of data |
michael@0 | 273 | * Starts a Serve_Client job for each incoming connection, to read |
michael@0 | 274 | * the data from the client and send it back to the client, unmodified. |
michael@0 | 275 | * Each client checks that data received from server is same as the |
michael@0 | 276 | * data it sent to the server. |
michael@0 | 277 | * Finally, the threadpool is shutdown |
michael@0 | 278 | */ |
michael@0 | 279 | static void PR_CALLBACK |
michael@0 | 280 | TCP_Server(void *arg) |
michael@0 | 281 | { |
michael@0 | 282 | PRThreadPool *tp = (PRThreadPool *) arg; |
michael@0 | 283 | Server_Param *sp; |
michael@0 | 284 | PRFileDesc *sockfd; |
michael@0 | 285 | PRNetAddr netaddr; |
michael@0 | 286 | PRMonitor *sc_mon; |
michael@0 | 287 | PRJob *jobp; |
michael@0 | 288 | int i; |
michael@0 | 289 | PRStatus rval; |
michael@0 | 290 | |
michael@0 | 291 | /* |
michael@0 | 292 | * Create a tcp socket |
michael@0 | 293 | */ |
michael@0 | 294 | if ((sockfd = PR_NewTCPSocket()) == NULL) { |
michael@0 | 295 | fprintf(stderr,"%s: PR_NewTCPSocket failed\n", program_name); |
michael@0 | 296 | return; |
michael@0 | 297 | } |
michael@0 | 298 | memset(&netaddr, 0 , sizeof(netaddr)); |
michael@0 | 299 | netaddr.inet.family = PR_AF_INET; |
michael@0 | 300 | netaddr.inet.port = PR_htons(TCP_SERVER_PORT); |
michael@0 | 301 | netaddr.inet.ip = PR_htonl(PR_INADDR_ANY); |
michael@0 | 302 | /* |
michael@0 | 303 | * try a few times to bind server's address, if addresses are in |
michael@0 | 304 | * use |
michael@0 | 305 | */ |
michael@0 | 306 | i = 0; |
michael@0 | 307 | while (PR_Bind(sockfd, &netaddr) < 0) { |
michael@0 | 308 | if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) { |
michael@0 | 309 | netaddr.inet.port += 2; |
michael@0 | 310 | if (i++ < SERVER_MAX_BIND_COUNT) |
michael@0 | 311 | continue; |
michael@0 | 312 | } |
michael@0 | 313 | fprintf(stderr,"%s: ERROR - PR_Bind failed\n", program_name); |
michael@0 | 314 | perror("PR_Bind"); |
michael@0 | 315 | failed_already=1; |
michael@0 | 316 | return; |
michael@0 | 317 | } |
michael@0 | 318 | |
michael@0 | 319 | if (PR_Listen(sockfd, 32) < 0) { |
michael@0 | 320 | fprintf(stderr,"%s: ERROR - PR_Listen failed\n", program_name); |
michael@0 | 321 | failed_already=1; |
michael@0 | 322 | return; |
michael@0 | 323 | } |
michael@0 | 324 | |
michael@0 | 325 | if (PR_GetSockName(sockfd, &netaddr) < 0) { |
michael@0 | 326 | fprintf(stderr,"%s: ERROR - PR_GetSockName failed\n", program_name); |
michael@0 | 327 | failed_already=1; |
michael@0 | 328 | return; |
michael@0 | 329 | } |
michael@0 | 330 | |
michael@0 | 331 | DPRINTF(( |
michael@0 | 332 | "TCP_Server: PR_BIND netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n", |
michael@0 | 333 | netaddr.inet.ip, netaddr.inet.port)); |
michael@0 | 334 | |
michael@0 | 335 | sp = PR_NEW(Server_Param); |
michael@0 | 336 | if (sp == NULL) { |
michael@0 | 337 | fprintf(stderr,"%s: PR_NEW failed\n", program_name); |
michael@0 | 338 | failed_already=1; |
michael@0 | 339 | return; |
michael@0 | 340 | } |
michael@0 | 341 | sp->iod.socket = sockfd; |
michael@0 | 342 | sp->iod.timeout = PR_SecondsToInterval(60); |
michael@0 | 343 | sp->datalen = tcp_mesg_size; |
michael@0 | 344 | sp->exit_mon = sc_mon; |
michael@0 | 345 | sp->job_counterp = &job_counter; |
michael@0 | 346 | sp->conn_counter = 0; |
michael@0 | 347 | sp->tp = tp; |
michael@0 | 348 | sp->netaddr = netaddr; |
michael@0 | 349 | |
michael@0 | 350 | /* create and cancel an io job */ |
michael@0 | 351 | jobp = PR_QueueJob_Accept(tp, &sp->iod, TCP_Server_Accept, sp, |
michael@0 | 352 | PR_FALSE); |
michael@0 | 353 | PR_ASSERT(NULL != jobp); |
michael@0 | 354 | rval = PR_CancelJob(jobp); |
michael@0 | 355 | PR_ASSERT(PR_SUCCESS == rval); |
michael@0 | 356 | |
michael@0 | 357 | /* |
michael@0 | 358 | * create the client process |
michael@0 | 359 | */ |
michael@0 | 360 | { |
michael@0 | 361 | #define MAX_ARGS 4 |
michael@0 | 362 | char *argv[MAX_ARGS + 1]; |
michael@0 | 363 | int index = 0; |
michael@0 | 364 | char port[32]; |
michael@0 | 365 | char path[1024 + sizeof("/thrpool_client")]; |
michael@0 | 366 | |
michael@0 | 367 | getcwd(path, sizeof(path)); |
michael@0 | 368 | |
michael@0 | 369 | (void)strcat(path, "/thrpool_client"); |
michael@0 | 370 | #ifdef XP_PC |
michael@0 | 371 | (void)strcat(path, ".exe"); |
michael@0 | 372 | #endif |
michael@0 | 373 | argv[index++] = path; |
michael@0 | 374 | sprintf(port,"%d",PR_ntohs(netaddr.inet.port)); |
michael@0 | 375 | if (_debug_on) |
michael@0 | 376 | { |
michael@0 | 377 | argv[index++] = "-d"; |
michael@0 | 378 | argv[index++] = "-p"; |
michael@0 | 379 | argv[index++] = port; |
michael@0 | 380 | argv[index++] = NULL; |
michael@0 | 381 | } else { |
michael@0 | 382 | argv[index++] = "-p"; |
michael@0 | 383 | argv[index++] = port; |
michael@0 | 384 | argv[index++] = NULL; |
michael@0 | 385 | } |
michael@0 | 386 | PR_ASSERT(MAX_ARGS >= (index - 1)); |
michael@0 | 387 | |
michael@0 | 388 | DPRINTF(("creating client process %s ...\n", path)); |
michael@0 | 389 | if (PR_FAILURE == PR_CreateProcessDetached(path, argv, NULL, NULL)) { |
michael@0 | 390 | fprintf(stderr, |
michael@0 | 391 | "thrpool_server: ERROR - PR_CreateProcessDetached failed\n"); |
michael@0 | 392 | failed_already=1; |
michael@0 | 393 | return; |
michael@0 | 394 | } |
michael@0 | 395 | } |
michael@0 | 396 | |
michael@0 | 397 | sc_mon = PR_NewMonitor(); |
michael@0 | 398 | if (sc_mon == NULL) { |
michael@0 | 399 | fprintf(stderr,"%s: PR_NewMonitor failed\n", program_name); |
michael@0 | 400 | failed_already=1; |
michael@0 | 401 | return; |
michael@0 | 402 | } |
michael@0 | 403 | |
michael@0 | 404 | sp->iod.socket = sockfd; |
michael@0 | 405 | sp->iod.timeout = PR_SecondsToInterval(60); |
michael@0 | 406 | sp->datalen = tcp_mesg_size; |
michael@0 | 407 | sp->exit_mon = sc_mon; |
michael@0 | 408 | sp->job_counterp = &job_counter; |
michael@0 | 409 | sp->conn_counter = 0; |
michael@0 | 410 | sp->tp = tp; |
michael@0 | 411 | sp->netaddr = netaddr; |
michael@0 | 412 | |
michael@0 | 413 | /* create and cancel a timer job */ |
michael@0 | 414 | jobp = PR_QueueJob_Timer(tp, PR_MillisecondsToInterval(5000), |
michael@0 | 415 | print_stats, sp, PR_FALSE); |
michael@0 | 416 | PR_ASSERT(NULL != jobp); |
michael@0 | 417 | rval = PR_CancelJob(jobp); |
michael@0 | 418 | PR_ASSERT(PR_SUCCESS == rval); |
michael@0 | 419 | |
michael@0 | 420 | DPRINTF(("TCP_Server: Accepting connections \n")); |
michael@0 | 421 | |
michael@0 | 422 | jobp = PR_QueueJob_Accept(tp, &sp->iod, TCP_Server_Accept, sp, |
michael@0 | 423 | PR_FALSE); |
michael@0 | 424 | PR_ASSERT(NULL != jobp); |
michael@0 | 425 | return; |
michael@0 | 426 | } |
michael@0 | 427 | |
michael@0 | 428 | static void |
michael@0 | 429 | TCP_Server_Accept(void *arg) |
michael@0 | 430 | { |
michael@0 | 431 | Server_Param *sp = (Server_Param *) arg; |
michael@0 | 432 | PRThreadPool *tp = sp->tp; |
michael@0 | 433 | Serve_Client_Param *scp; |
michael@0 | 434 | PRFileDesc *newsockfd; |
michael@0 | 435 | PRJob *jobp; |
michael@0 | 436 | |
michael@0 | 437 | if ((newsockfd = PR_Accept(sp->iod.socket, &sp->netaddr, |
michael@0 | 438 | PR_INTERVAL_NO_TIMEOUT)) == NULL) { |
michael@0 | 439 | fprintf(stderr,"%s: ERROR - PR_Accept failed\n", program_name); |
michael@0 | 440 | failed_already=1; |
michael@0 | 441 | goto exit; |
michael@0 | 442 | } |
michael@0 | 443 | scp = PR_NEW(Serve_Client_Param); |
michael@0 | 444 | if (scp == NULL) { |
michael@0 | 445 | fprintf(stderr,"%s: PR_NEW failed\n", program_name); |
michael@0 | 446 | failed_already=1; |
michael@0 | 447 | goto exit; |
michael@0 | 448 | } |
michael@0 | 449 | |
michael@0 | 450 | /* |
michael@0 | 451 | * Start a Serve_Client job for each incoming connection |
michael@0 | 452 | */ |
michael@0 | 453 | scp->iod.socket = newsockfd; |
michael@0 | 454 | scp->iod.timeout = PR_SecondsToInterval(60); |
michael@0 | 455 | scp->datalen = tcp_mesg_size; |
michael@0 | 456 | scp->exit_mon = sp->exit_mon; |
michael@0 | 457 | scp->job_counterp = sp->job_counterp; |
michael@0 | 458 | scp->tp = sp->tp; |
michael@0 | 459 | |
michael@0 | 460 | PR_EnterMonitor(sp->exit_mon); |
michael@0 | 461 | (*sp->job_counterp)++; |
michael@0 | 462 | PR_ExitMonitor(sp->exit_mon); |
michael@0 | 463 | jobp = PR_QueueJob(tp, Serve_Client, scp, |
michael@0 | 464 | PR_FALSE); |
michael@0 | 465 | |
michael@0 | 466 | PR_ASSERT(NULL != jobp); |
michael@0 | 467 | DPRINTF(("TCP_Server: Created Serve_Client = 0x%lx\n", jobp)); |
michael@0 | 468 | |
michael@0 | 469 | /* |
michael@0 | 470 | * single-threaded update; no lock needed |
michael@0 | 471 | */ |
michael@0 | 472 | sp->conn_counter++; |
michael@0 | 473 | if (sp->conn_counter < |
michael@0 | 474 | (num_tcp_clients * num_tcp_connections_per_client)) { |
michael@0 | 475 | jobp = PR_QueueJob_Accept(tp, &sp->iod, TCP_Server_Accept, sp, |
michael@0 | 476 | PR_FALSE); |
michael@0 | 477 | PR_ASSERT(NULL != jobp); |
michael@0 | 478 | return; |
michael@0 | 479 | } |
michael@0 | 480 | jobp = PR_QueueJob_Timer(tp, PR_MillisecondsToInterval(500), |
michael@0 | 481 | print_stats, sp, PR_FALSE); |
michael@0 | 482 | |
michael@0 | 483 | PR_ASSERT(NULL != jobp); |
michael@0 | 484 | DPRINTF(("TCP_Server: Created print_stats timer job = 0x%lx\n", jobp)); |
michael@0 | 485 | |
michael@0 | 486 | exit: |
michael@0 | 487 | PR_EnterMonitor(sp->exit_mon); |
michael@0 | 488 | /* Wait for server jobs to finish */ |
michael@0 | 489 | while (0 != *sp->job_counterp) { |
michael@0 | 490 | PR_Wait(sp->exit_mon, PR_INTERVAL_NO_TIMEOUT); |
michael@0 | 491 | DPRINTF(("TCP_Server: conn_counter = %d\n", |
michael@0 | 492 | *sp->job_counterp)); |
michael@0 | 493 | } |
michael@0 | 494 | |
michael@0 | 495 | PR_ExitMonitor(sp->exit_mon); |
michael@0 | 496 | if (sp->iod.socket) { |
michael@0 | 497 | PR_Close(sp->iod.socket); |
michael@0 | 498 | } |
michael@0 | 499 | PR_DestroyMonitor(sp->exit_mon); |
michael@0 | 500 | printf("%30s","TCP_Socket_Client_Server_Test:"); |
michael@0 | 501 | printf("%2ld Server %2ld Clients %2ld connections_per_client\n",1l, |
michael@0 | 502 | num_tcp_clients, num_tcp_connections_per_client); |
michael@0 | 503 | printf("%30s %2ld messages_per_connection %4ld bytes_per_message\n",":", |
michael@0 | 504 | num_tcp_mesgs_per_connection, tcp_mesg_size); |
michael@0 | 505 | |
michael@0 | 506 | DPRINTF(("%s: calling PR_ShutdownThreadPool\n", program_name)); |
michael@0 | 507 | PR_ShutdownThreadPool(sp->tp); |
michael@0 | 508 | PR_DELETE(sp); |
michael@0 | 509 | } |
michael@0 | 510 | |
michael@0 | 511 | /************************************************************************/ |
michael@0 | 512 | |
michael@0 | 513 | #define DEFAULT_INITIAL_THREADS 4 |
michael@0 | 514 | #define DEFAULT_MAX_THREADS 100 |
michael@0 | 515 | #define DEFAULT_STACKSIZE (512 * 1024) |
michael@0 | 516 | |
michael@0 | 517 | int main(int argc, char **argv) |
michael@0 | 518 | { |
michael@0 | 519 | PRInt32 initial_threads = DEFAULT_INITIAL_THREADS; |
michael@0 | 520 | PRInt32 max_threads = DEFAULT_MAX_THREADS; |
michael@0 | 521 | PRInt32 stacksize = DEFAULT_STACKSIZE; |
michael@0 | 522 | PRThreadPool *tp = NULL; |
michael@0 | 523 | PRStatus rv; |
michael@0 | 524 | PRJob *jobp; |
michael@0 | 525 | |
michael@0 | 526 | /* |
michael@0 | 527 | * -d debug mode |
michael@0 | 528 | */ |
michael@0 | 529 | PLOptStatus os; |
michael@0 | 530 | PLOptState *opt; |
michael@0 | 531 | |
michael@0 | 532 | program_name = argv[0]; |
michael@0 | 533 | opt = PL_CreateOptState(argc, argv, "d"); |
michael@0 | 534 | while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) |
michael@0 | 535 | { |
michael@0 | 536 | if (PL_OPT_BAD == os) continue; |
michael@0 | 537 | switch (opt->option) |
michael@0 | 538 | { |
michael@0 | 539 | case 'd': /* debug mode */ |
michael@0 | 540 | _debug_on = 1; |
michael@0 | 541 | break; |
michael@0 | 542 | default: |
michael@0 | 543 | break; |
michael@0 | 544 | } |
michael@0 | 545 | } |
michael@0 | 546 | PL_DestroyOptState(opt); |
michael@0 | 547 | |
michael@0 | 548 | PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); |
michael@0 | 549 | PR_STDIO_INIT(); |
michael@0 | 550 | |
michael@0 | 551 | PR_SetConcurrency(4); |
michael@0 | 552 | |
michael@0 | 553 | tp = PR_CreateThreadPool(initial_threads, max_threads, stacksize); |
michael@0 | 554 | if (NULL == tp) { |
michael@0 | 555 | printf("PR_CreateThreadPool failed\n"); |
michael@0 | 556 | failed_already=1; |
michael@0 | 557 | goto done; |
michael@0 | 558 | } |
michael@0 | 559 | jobp = PR_QueueJob(tp, TCP_Server, tp, PR_TRUE); |
michael@0 | 560 | rv = PR_JoinJob(jobp); |
michael@0 | 561 | PR_ASSERT(PR_SUCCESS == rv); |
michael@0 | 562 | |
michael@0 | 563 | DPRINTF(("%s: calling PR_JoinThreadPool\n", program_name)); |
michael@0 | 564 | rv = PR_JoinThreadPool(tp); |
michael@0 | 565 | PR_ASSERT(PR_SUCCESS == rv); |
michael@0 | 566 | DPRINTF(("%s: returning from PR_JoinThreadPool\n", program_name)); |
michael@0 | 567 | |
michael@0 | 568 | done: |
michael@0 | 569 | PR_Cleanup(); |
michael@0 | 570 | if (failed_already) return 1; |
michael@0 | 571 | else return 0; |
michael@0 | 572 | } |