1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/tests/io_timeout.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,256 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 +** Test socket IO timeouts 1.11 +** 1.12 +** 1.13 +** 1.14 +** 1.15 +** Modification History: 1.16 +** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. 1.17 +** The debug mode will print all of the printfs associated with this test. 1.18 +** The regress mode will be the default mode. Since the regress tool limits 1.19 +** the output to a one line status:PASS or FAIL,all of the printf statements 1.20 +** have been handled with an if (debug_mode) statement. 1.21 +***********************************************************************/ 1.22 +/*********************************************************************** 1.23 +** Includes 1.24 +***********************************************************************/ 1.25 +/* Used to get the command line option */ 1.26 +#include "plgetopt.h" 1.27 + 1.28 +#include <stdio.h> 1.29 +#include "nspr.h" 1.30 + 1.31 +#define NUM_THREADS 1 1.32 +#define BASE_PORT 8000 1.33 +#define DEFAULT_ACCEPT_TIMEOUT 2 1.34 + 1.35 +typedef struct threadInfo { 1.36 + PRInt16 id; 1.37 + PRInt16 accept_timeout; 1.38 + PRLock *dead_lock; 1.39 + PRCondVar *dead_cv; 1.40 + PRInt32 *alive; 1.41 +} threadInfo; 1.42 + 1.43 +PRIntn failed_already = 0; 1.44 +PRIntn debug_mode = 0; 1.45 + 1.46 +#define LOCAL_SCOPE_STRING "LOCAL scope" 1.47 +#define GLOBAL_SCOPE_STRING "GLOBAL scope" 1.48 +#define GLOBAL_BOUND_SCOPE_STRING "GLOBAL_BOUND scope" 1.49 + 1.50 +void 1.51 +thread_main(void *_info) 1.52 +{ 1.53 + threadInfo *info = (threadInfo *)_info; 1.54 + PRNetAddr listenAddr; 1.55 + PRNetAddr clientAddr; 1.56 + PRFileDesc *listenSock = NULL; 1.57 + PRFileDesc *clientSock; 1.58 + PRStatus rv; 1.59 + PRThreadScope tscope; 1.60 + char *scope_str; 1.61 + 1.62 + 1.63 + if (debug_mode) 1.64 + printf("thread %d is alive\n", info->id); 1.65 + tscope = PR_GetThreadScope(PR_GetCurrentThread()); 1.66 + 1.67 + switch(tscope) { 1.68 + case PR_LOCAL_THREAD: 1.69 + scope_str = LOCAL_SCOPE_STRING; 1.70 + break; 1.71 + case PR_GLOBAL_THREAD: 1.72 + scope_str = GLOBAL_SCOPE_STRING; 1.73 + break; 1.74 + case PR_GLOBAL_BOUND_THREAD: 1.75 + scope_str = GLOBAL_BOUND_SCOPE_STRING; 1.76 + break; 1.77 + default: 1.78 + PR_ASSERT(!"Invalid thread scope"); 1.79 + break; 1.80 + } 1.81 + printf("thread id %d, scope %s\n", info->id, scope_str); 1.82 + 1.83 + listenSock = PR_NewTCPSocket(); 1.84 + if (!listenSock) { 1.85 + if (debug_mode) 1.86 + printf("unable to create listen socket\n"); 1.87 + failed_already=1; 1.88 + goto dead; 1.89 + } 1.90 + 1.91 + listenAddr.inet.family = PR_AF_INET; 1.92 + listenAddr.inet.port = PR_htons(BASE_PORT + info->id); 1.93 + listenAddr.inet.ip = PR_htonl(PR_INADDR_ANY); 1.94 + rv = PR_Bind(listenSock, &listenAddr); 1.95 + if (rv == PR_FAILURE) { 1.96 + if (debug_mode) 1.97 + printf("unable to bind\n"); 1.98 + failed_already=1; 1.99 + goto dead; 1.100 + } 1.101 + 1.102 + rv = PR_Listen(listenSock, 4); 1.103 + if (rv == PR_FAILURE) { 1.104 + if (debug_mode) 1.105 + printf("unable to listen\n"); 1.106 + failed_already=1; 1.107 + goto dead; 1.108 + } 1.109 + 1.110 + if (debug_mode) 1.111 + printf("thread %d going into accept for %d seconds\n", 1.112 + info->id, info->accept_timeout + info->id); 1.113 + 1.114 + clientSock = PR_Accept(listenSock, &clientAddr, PR_SecondsToInterval(info->accept_timeout +info->id)); 1.115 + 1.116 + if (clientSock == NULL) { 1.117 + if (PR_GetError() == PR_IO_TIMEOUT_ERROR) { 1.118 + if (debug_mode) { 1.119 + printf("PR_Accept() timeout worked!\n"); 1.120 + printf("TEST PASSED! PR_Accept() returned error %d\n", 1.121 + PR_IO_TIMEOUT_ERROR); 1.122 + } 1.123 + } else { 1.124 + if (debug_mode) 1.125 + printf("TEST FAILED! PR_Accept() returned error %d\n", 1.126 + PR_GetError()); 1.127 + failed_already=1; 1.128 + } 1.129 + } else { 1.130 + if (debug_mode) 1.131 + printf ("TEST FAILED! PR_Accept() succeeded?\n"); 1.132 + failed_already=1; 1.133 + PR_Close(clientSock); 1.134 + } 1.135 + 1.136 +dead: 1.137 + if (listenSock) { 1.138 + PR_Close(listenSock); 1.139 + } 1.140 + PR_Lock(info->dead_lock); 1.141 + (*info->alive)--; 1.142 + PR_NotifyCondVar(info->dead_cv); 1.143 + PR_Unlock(info->dead_lock); 1.144 + 1.145 + if (debug_mode) 1.146 + printf("thread %d is dead\n", info->id); 1.147 + 1.148 + PR_Free(info); 1.149 +} 1.150 + 1.151 +void 1.152 +thread_test(PRThreadScope scope, PRInt32 num_threads) 1.153 +{ 1.154 + PRInt32 index; 1.155 + PRThread *thr; 1.156 + PRLock *dead_lock; 1.157 + PRCondVar *dead_cv; 1.158 + PRInt32 alive; 1.159 + 1.160 + if (debug_mode) 1.161 + printf("IO Timeout test started with %d threads\n", num_threads); 1.162 + 1.163 + dead_lock = PR_NewLock(); 1.164 + dead_cv = PR_NewCondVar(dead_lock); 1.165 + alive = num_threads; 1.166 + 1.167 + for (index = 0; index < num_threads; index++) { 1.168 + threadInfo *info = (threadInfo *)PR_Malloc(sizeof(threadInfo)); 1.169 + 1.170 + info->id = index; 1.171 + info->dead_lock = dead_lock; 1.172 + info->dead_cv = dead_cv; 1.173 + info->alive = &alive; 1.174 + info->accept_timeout = DEFAULT_ACCEPT_TIMEOUT; 1.175 + 1.176 + thr = PR_CreateThread( PR_USER_THREAD, 1.177 + thread_main, 1.178 + (void *)info, 1.179 + PR_PRIORITY_NORMAL, 1.180 + scope, 1.181 + PR_UNJOINABLE_THREAD, 1.182 + 0); 1.183 + 1.184 + if (!thr) { 1.185 + printf("Failed to create thread, error = %d(%d)\n", 1.186 + PR_GetError(), PR_GetOSError()); 1.187 + failed_already=1; 1.188 + 1.189 + PR_Lock(dead_lock); 1.190 + alive--; 1.191 + PR_Unlock(dead_lock); 1.192 + } 1.193 + } 1.194 + 1.195 + PR_Lock(dead_lock); 1.196 + while(alive) { 1.197 + if (debug_mode) 1.198 + printf("main loop awake; alive = %d\n", alive); 1.199 + PR_WaitCondVar(dead_cv, PR_INTERVAL_NO_TIMEOUT); 1.200 + } 1.201 + PR_Unlock(dead_lock); 1.202 + 1.203 + PR_DestroyCondVar(dead_cv); 1.204 + PR_DestroyLock(dead_lock); 1.205 +} 1.206 + 1.207 +int main(int argc, char **argv) 1.208 +{ 1.209 + PRInt32 num_threads = 0; 1.210 + 1.211 + /* The command line argument: -d is used to determine if the test is being run 1.212 + in debug mode. The regress tool requires only one line output:PASS or FAIL. 1.213 + All of the printfs associated with this test has been handled with a if (debug_mode) 1.214 + test. 1.215 + Usage: test_name [-d] [-t <threads>] 1.216 + */ 1.217 + PLOptStatus os; 1.218 + PLOptState *opt = PL_CreateOptState(argc, argv, "dt:"); 1.219 + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) 1.220 + { 1.221 + if (PL_OPT_BAD == os) continue; 1.222 + switch (opt->option) 1.223 + { 1.224 + case 'd': /* debug mode */ 1.225 + debug_mode = 1; 1.226 + break; 1.227 + case 't': /* threads to involve */ 1.228 + num_threads = atoi(opt->value); 1.229 + break; 1.230 + default: 1.231 + break; 1.232 + } 1.233 + } 1.234 + PL_DestroyOptState(opt); 1.235 + 1.236 + /* main test */ 1.237 + 1.238 + if (0 == num_threads) 1.239 + num_threads = NUM_THREADS; 1.240 + 1.241 + PR_Init(PR_USER_THREAD, PR_PRIORITY_LOW, 0); 1.242 + PR_STDIO_INIT(); 1.243 + 1.244 + printf("test with global bound thread\n"); 1.245 + thread_test(PR_GLOBAL_BOUND_THREAD, num_threads); 1.246 + 1.247 + printf("test with local thread\n"); 1.248 + thread_test(PR_LOCAL_THREAD, num_threads); 1.249 + 1.250 + printf("test with global thread\n"); 1.251 + thread_test(PR_GLOBAL_THREAD, num_threads); 1.252 + 1.253 + PR_Cleanup(); 1.254 + 1.255 + if (failed_already) 1.256 + return 1; 1.257 + else 1.258 + return 0; 1.259 +}