io_timeout.c (6552B)
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/. */ 5 6 /* 7 ** Test socket IO timeouts 8 ** 9 ** 10 ** 11 ** 12 ** Modification History: 13 ** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. 14 ** The debug mode will print all of the printfs associated with this 15 *test. 16 ** The regress mode will be the default mode. Since the regress tool 17 *limits 18 ** the output to a one line status:PASS or FAIL,all of the printf 19 *statements 20 ** have been handled with an if (debug_mode) statement. 21 ***********************************************************************/ 22 /*********************************************************************** 23 ** Includes 24 ***********************************************************************/ 25 /* Used to get the command line option */ 26 #include "plgetopt.h" 27 28 #include <stdio.h> 29 #include "nspr.h" 30 31 #define NUM_THREADS 1 32 #define BASE_PORT 8000 33 #define DEFAULT_ACCEPT_TIMEOUT 2 34 35 typedef struct threadInfo { 36 PRInt16 id; 37 PRInt16 accept_timeout; 38 PRLock* dead_lock; 39 PRCondVar* dead_cv; 40 PRInt32* alive; 41 } threadInfo; 42 43 PRIntn failed_already = 0; 44 PRIntn debug_mode = 0; 45 46 #define LOCAL_SCOPE_STRING "LOCAL scope" 47 #define GLOBAL_SCOPE_STRING "GLOBAL scope" 48 #define GLOBAL_BOUND_SCOPE_STRING "GLOBAL_BOUND scope" 49 50 void thread_main(void* _info) { 51 threadInfo* info = (threadInfo*)_info; 52 PRNetAddr listenAddr; 53 PRNetAddr clientAddr; 54 PRFileDesc* listenSock = NULL; 55 PRFileDesc* clientSock; 56 PRStatus rv; 57 PRThreadScope tscope; 58 char* scope_str; 59 60 if (debug_mode) { 61 printf("thread %d is alive\n", info->id); 62 } 63 tscope = PR_GetThreadScope(PR_GetCurrentThread()); 64 65 switch (tscope) { 66 case PR_LOCAL_THREAD: 67 scope_str = LOCAL_SCOPE_STRING; 68 break; 69 case PR_GLOBAL_THREAD: 70 scope_str = GLOBAL_SCOPE_STRING; 71 break; 72 case PR_GLOBAL_BOUND_THREAD: 73 scope_str = GLOBAL_BOUND_SCOPE_STRING; 74 break; 75 default: 76 PR_NOT_REACHED("Invalid thread scope"); 77 break; 78 } 79 printf("thread id %d, scope %s\n", info->id, scope_str); 80 81 listenSock = PR_NewTCPSocket(); 82 if (!listenSock) { 83 if (debug_mode) { 84 printf("unable to create listen socket\n"); 85 } 86 failed_already = 1; 87 goto dead; 88 } 89 90 listenAddr.inet.family = PR_AF_INET; 91 listenAddr.inet.port = PR_htons(BASE_PORT + info->id); 92 listenAddr.inet.ip = PR_htonl(PR_INADDR_ANY); 93 rv = PR_Bind(listenSock, &listenAddr); 94 if (rv == PR_FAILURE) { 95 if (debug_mode) { 96 printf("unable to bind\n"); 97 } 98 failed_already = 1; 99 goto dead; 100 } 101 102 rv = PR_Listen(listenSock, 4); 103 if (rv == PR_FAILURE) { 104 if (debug_mode) { 105 printf("unable to listen\n"); 106 } 107 failed_already = 1; 108 goto dead; 109 } 110 111 if (debug_mode) 112 printf("thread %d going into accept for %d seconds\n", info->id, 113 info->accept_timeout + info->id); 114 115 clientSock = PR_Accept(listenSock, &clientAddr, 116 PR_SecondsToInterval(info->accept_timeout + info->id)); 117 118 if (clientSock == NULL) { 119 if (PR_GetError() == PR_IO_TIMEOUT_ERROR) { 120 if (debug_mode) { 121 printf("PR_Accept() timeout worked!\n"); 122 printf("TEST PASSED! PR_Accept() returned error %d\n", 123 PR_IO_TIMEOUT_ERROR); 124 } 125 } else { 126 if (debug_mode) 127 printf("TEST FAILED! PR_Accept() returned error %d\n", PR_GetError()); 128 failed_already = 1; 129 } 130 } else { 131 if (debug_mode) { 132 printf("TEST FAILED! PR_Accept() succeeded?\n"); 133 } 134 failed_already = 1; 135 PR_Close(clientSock); 136 } 137 138 dead: 139 if (listenSock) { 140 PR_Close(listenSock); 141 } 142 PR_Lock(info->dead_lock); 143 (*info->alive)--; 144 PR_NotifyCondVar(info->dead_cv); 145 PR_Unlock(info->dead_lock); 146 147 if (debug_mode) { 148 printf("thread %d is dead\n", info->id); 149 } 150 151 PR_Free(info); 152 } 153 154 void thread_test(PRThreadScope scope, PRInt32 num_threads) { 155 PRInt32 index; 156 PRThread* thr; 157 PRLock* dead_lock; 158 PRCondVar* dead_cv; 159 PRInt32 alive; 160 161 if (debug_mode) { 162 printf("IO Timeout test started with %d threads\n", num_threads); 163 } 164 165 dead_lock = PR_NewLock(); 166 dead_cv = PR_NewCondVar(dead_lock); 167 alive = num_threads; 168 169 for (index = 0; index < num_threads; index++) { 170 threadInfo* info = (threadInfo*)PR_Malloc(sizeof(threadInfo)); 171 172 info->id = index; 173 info->dead_lock = dead_lock; 174 info->dead_cv = dead_cv; 175 info->alive = &alive; 176 info->accept_timeout = DEFAULT_ACCEPT_TIMEOUT; 177 178 thr = PR_CreateThread(PR_USER_THREAD, thread_main, (void*)info, 179 PR_PRIORITY_NORMAL, scope, PR_UNJOINABLE_THREAD, 0); 180 181 if (!thr) { 182 printf("Failed to create thread, error = %d(%d)\n", PR_GetError(), 183 PR_GetOSError()); 184 failed_already = 1; 185 186 PR_Lock(dead_lock); 187 alive--; 188 PR_Unlock(dead_lock); 189 } 190 } 191 192 PR_Lock(dead_lock); 193 while (alive) { 194 if (debug_mode) { 195 printf("main loop awake; alive = %d\n", alive); 196 } 197 PR_WaitCondVar(dead_cv, PR_INTERVAL_NO_TIMEOUT); 198 } 199 PR_Unlock(dead_lock); 200 201 PR_DestroyCondVar(dead_cv); 202 PR_DestroyLock(dead_lock); 203 } 204 205 int main(int argc, char** argv) { 206 PRInt32 num_threads = 0; 207 208 /* The command line argument: -d is used to determine if the test is being run 209 in debug mode. The regress tool requires only one line output:PASS or FAIL. 210 All of the printfs associated with this test has been handled with a if 211 (debug_mode) test. Usage: test_name [-d] [-t <threads>] 212 */ 213 PLOptStatus os; 214 PLOptState* opt = PL_CreateOptState(argc, argv, "dt:"); 215 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { 216 if (PL_OPT_BAD == os) { 217 continue; 218 } 219 switch (opt->option) { 220 case 'd': /* debug mode */ 221 debug_mode = 1; 222 break; 223 case 't': /* threads to involve */ 224 num_threads = atoi(opt->value); 225 break; 226 default: 227 break; 228 } 229 } 230 PL_DestroyOptState(opt); 231 232 /* main test */ 233 234 if (0 == num_threads) { 235 num_threads = NUM_THREADS; 236 } 237 238 PR_Init(PR_USER_THREAD, PR_PRIORITY_LOW, 0); 239 240 printf("test with global bound thread\n"); 241 thread_test(PR_GLOBAL_BOUND_THREAD, num_threads); 242 243 printf("test with local thread\n"); 244 thread_test(PR_LOCAL_THREAD, num_threads); 245 246 printf("test with global thread\n"); 247 thread_test(PR_GLOBAL_THREAD, num_threads); 248 249 PR_Cleanup(); 250 251 if (failed_already) { 252 return 1; 253 } else { 254 return 0; 255 } 256 }