intrupt.c (8666B)
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 * File: intrupt.c 8 * Purpose: testing thread interrupts 9 */ 10 11 #include "plgetopt.h" 12 #include "prcvar.h" 13 #include "prerror.h" 14 #include "prinit.h" 15 #include "prinrval.h" 16 #include "prio.h" 17 #include "prlock.h" 18 #include "prlog.h" 19 #include "prthread.h" 20 #include "prtypes.h" 21 #include "prnetdb.h" 22 23 #include <stdio.h> 24 #include <string.h> 25 26 #define DEFAULT_TCP_PORT 12500 27 28 static PRLock* ml = NULL; 29 static PRCondVar* cv = NULL; 30 31 static PRBool passed = PR_TRUE; 32 static PRBool debug_mode = PR_FALSE; 33 static PRThreadScope thread_scope = PR_LOCAL_THREAD; 34 35 static void PR_CALLBACK AbortCV(void* arg) { 36 PRStatus rv; 37 PRThread* me = PR_GetCurrentThread(); 38 39 /* some other thread (main) is doing the interrupt */ 40 PR_Lock(ml); 41 rv = PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT); 42 if (debug_mode) { 43 printf("Expected interrupt on wait CV and "); 44 } 45 if (PR_FAILURE == rv) { 46 if (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) { 47 if (debug_mode) { 48 printf("got it\n"); 49 } 50 } else { 51 if (debug_mode) { 52 printf("got random error\n"); 53 } 54 passed = PR_FALSE; 55 } 56 } else { 57 if (debug_mode) { 58 printf("got a successful completion\n"); 59 } 60 passed = PR_FALSE; 61 } 62 63 rv = PR_WaitCondVar(cv, 10); 64 if (debug_mode) { 65 printf("Expected success on wait CV and %s\n", 66 (PR_SUCCESS == rv) ? "got it" : "failed"); 67 } 68 passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE; 69 70 /* interrupt myself, then clear */ 71 PR_Interrupt(me); 72 PR_ClearInterrupt(); 73 rv = PR_WaitCondVar(cv, 10); 74 if (debug_mode) { 75 printf("Expected success on wait CV and "); 76 if (PR_FAILURE == rv) { 77 printf("%s\n", (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) 78 ? "got interrupted" 79 : "a random failure"); 80 } 81 printf("got it\n"); 82 } 83 passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE; 84 85 /* set, then wait - interrupt - then wait again */ 86 PR_Interrupt(me); 87 rv = PR_WaitCondVar(cv, 10); 88 if (debug_mode) { 89 printf("Expected interrupt on wait CV and "); 90 } 91 if (PR_FAILURE == rv) { 92 if (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) { 93 if (debug_mode) { 94 printf("got it\n"); 95 } 96 } else { 97 if (debug_mode) { 98 printf("failed\n"); 99 } 100 passed = PR_FALSE; 101 } 102 } else { 103 if (debug_mode) { 104 printf("got a successful completion\n"); 105 } 106 passed = PR_FALSE; 107 } 108 109 rv = PR_WaitCondVar(cv, 10); 110 if (debug_mode) { 111 printf("Expected success on wait CV and %s\n", 112 (PR_SUCCESS == rv) ? "got it" : "failed"); 113 } 114 passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE; 115 116 PR_Unlock(ml); 117 118 } /* AbortCV */ 119 120 static void PR_CALLBACK AbortIO(void* arg) { 121 PRStatus rv; 122 PR_Sleep(PR_SecondsToInterval(2)); 123 rv = PR_Interrupt((PRThread*)arg); 124 PR_ASSERT(PR_SUCCESS == rv); 125 } /* AbortIO */ 126 127 static void PR_CALLBACK AbortJoin(void* arg) {} /* AbortJoin */ 128 129 static void setup_listen_socket(PRFileDesc** listner, PRNetAddr* netaddr) { 130 PRStatus rv; 131 PRInt16 port = DEFAULT_TCP_PORT; 132 133 *listner = PR_NewTCPSocket(); 134 PR_ASSERT(*listner != NULL); 135 memset(netaddr, 0, sizeof(*netaddr)); 136 (*netaddr).inet.ip = PR_htonl(PR_INADDR_ANY); 137 (*netaddr).inet.family = PR_AF_INET; 138 do { 139 (*netaddr).inet.port = PR_htons(port); 140 rv = PR_Bind(*listner, netaddr); 141 port += 1; 142 PR_ASSERT(port < (DEFAULT_TCP_PORT + 10)); 143 } while (PR_FAILURE == rv); 144 145 rv = PR_Listen(*listner, 5); 146 147 if (PR_GetSockName(*listner, netaddr) < 0) { 148 if (debug_mode) { 149 printf("intrupt: ERROR - PR_GetSockName failed\n"); 150 } 151 passed = PR_FALSE; 152 return; 153 } 154 } 155 156 static void PR_CALLBACK IntrBlock(void* arg) { 157 PRStatus rv; 158 PRNetAddr netaddr; 159 PRFileDesc* listner; 160 161 /* some other thread (main) is doing the interrupt */ 162 /* block the interrupt */ 163 PR_BlockInterrupt(); 164 PR_Lock(ml); 165 rv = PR_WaitCondVar(cv, PR_SecondsToInterval(4)); 166 PR_Unlock(ml); 167 if (debug_mode) { 168 printf("Expected success on wait CV and "); 169 if (PR_FAILURE == rv) { 170 printf("%s\n", (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) 171 ? "got interrupted" 172 : "got a random failure"); 173 } else { 174 printf("got it\n"); 175 } 176 } 177 passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE; 178 179 setup_listen_socket(&listner, &netaddr); 180 PR_UnblockInterrupt(); 181 if (PR_Accept(listner, &netaddr, PR_INTERVAL_NO_TIMEOUT) == NULL) { 182 PRInt32 error = PR_GetError(); 183 if (debug_mode) { 184 printf("Expected interrupt on PR_Accept() and "); 185 } 186 if (PR_PENDING_INTERRUPT_ERROR == error) { 187 if (debug_mode) { 188 printf("got it\n"); 189 } 190 } else { 191 if (debug_mode) { 192 printf("failed\n"); 193 } 194 passed = PR_FALSE; 195 } 196 } else { 197 if (debug_mode) { 198 printf("Failed to interrupt PR_Accept()\n"); 199 } 200 passed = PR_FALSE; 201 } 202 203 (void)PR_Close(listner); 204 listner = NULL; 205 } /* TestIntrBlock */ 206 207 void PR_CALLBACK Intrupt(void* arg) { 208 PRStatus rv; 209 PRNetAddr netaddr; 210 PRFileDesc* listner; 211 PRThread *abortCV, *abortIO, *abortJoin, *intrBlock; 212 213 ml = PR_NewLock(); 214 cv = PR_NewCondVar(ml); 215 216 /* Part I */ 217 if (debug_mode) { 218 printf("Part I\n"); 219 } 220 abortCV = PR_CreateThread(PR_USER_THREAD, AbortCV, 0, PR_PRIORITY_NORMAL, 221 thread_scope, PR_JOINABLE_THREAD, 0); 222 223 PR_Sleep(PR_SecondsToInterval(2)); 224 rv = PR_Interrupt(abortCV); 225 PR_ASSERT(PR_SUCCESS == rv); 226 rv = PR_JoinThread(abortCV); 227 PR_ASSERT(PR_SUCCESS == rv); 228 229 /* Part II */ 230 if (debug_mode) { 231 printf("Part II\n"); 232 } 233 abortJoin = PR_CreateThread(PR_USER_THREAD, AbortJoin, 0, PR_PRIORITY_NORMAL, 234 thread_scope, PR_JOINABLE_THREAD, 0); 235 PR_Sleep(PR_SecondsToInterval(2)); 236 if (debug_mode) { 237 printf("Expecting to interrupt an exited thread "); 238 } 239 rv = PR_Interrupt(abortJoin); 240 PR_ASSERT(PR_SUCCESS == rv); 241 rv = PR_JoinThread(abortJoin); 242 PR_ASSERT(PR_SUCCESS == rv); 243 if (debug_mode) { 244 printf("and succeeded\n"); 245 } 246 247 /* Part III */ 248 if (debug_mode) { 249 printf("Part III\n"); 250 } 251 setup_listen_socket(&listner, &netaddr); 252 abortIO = 253 PR_CreateThread(PR_USER_THREAD, AbortIO, PR_GetCurrentThread(), 254 PR_PRIORITY_NORMAL, thread_scope, PR_JOINABLE_THREAD, 0); 255 256 if (PR_Accept(listner, &netaddr, PR_INTERVAL_NO_TIMEOUT) == NULL) { 257 PRInt32 error = PR_GetError(); 258 if (debug_mode) { 259 printf("Expected interrupt on PR_Accept() and "); 260 } 261 if (PR_PENDING_INTERRUPT_ERROR == error) { 262 if (debug_mode) { 263 printf("got it\n"); 264 } 265 } else { 266 if (debug_mode) { 267 printf("failed\n"); 268 } 269 passed = PR_FALSE; 270 } 271 } else { 272 if (debug_mode) { 273 printf("Failed to interrupt PR_Accept()\n"); 274 } 275 passed = PR_FALSE; 276 } 277 278 (void)PR_Close(listner); 279 listner = NULL; 280 281 rv = PR_JoinThread(abortIO); 282 PR_ASSERT(PR_SUCCESS == rv); 283 /* Part VI */ 284 if (debug_mode) { 285 printf("Part VI\n"); 286 } 287 intrBlock = PR_CreateThread(PR_USER_THREAD, IntrBlock, 0, PR_PRIORITY_NORMAL, 288 thread_scope, PR_JOINABLE_THREAD, 0); 289 290 PR_Sleep(PR_SecondsToInterval(2)); 291 rv = PR_Interrupt(intrBlock); 292 PR_ASSERT(PR_SUCCESS == rv); 293 rv = PR_JoinThread(intrBlock); 294 PR_ASSERT(PR_SUCCESS == rv); 295 296 PR_DestroyCondVar(cv); 297 PR_DestroyLock(ml); 298 } /* Intrupt */ 299 300 int main(int argc, char** argv) { 301 PRThread* intrupt; 302 PLOptStatus os; 303 PLOptState* opt = PL_CreateOptState(argc, argv, "dG"); 304 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { 305 if (PL_OPT_BAD == os) { 306 continue; 307 } 308 switch (opt->option) { 309 case 'd': /* debug mode */ 310 debug_mode = PR_TRUE; 311 break; 312 case 'G': /* use global threads */ 313 thread_scope = PR_GLOBAL_THREAD; 314 break; 315 } 316 } 317 PL_DestroyOptState(opt); 318 intrupt = PR_CreateThread(PR_USER_THREAD, Intrupt, NULL, PR_PRIORITY_NORMAL, 319 thread_scope, PR_JOINABLE_THREAD, 0); 320 if (intrupt == NULL) { 321 fprintf(stderr, "cannot create thread\n"); 322 passed = PR_FALSE; 323 } else { 324 PRStatus rv; 325 rv = PR_JoinThread(intrupt); 326 PR_ASSERT(rv == PR_SUCCESS); 327 } 328 printf("%s\n", ((passed) ? "PASSED" : "FAILED")); 329 return ((passed) ? 0 : 1); 330 } /* main */ 331 332 /* intrupt.c */