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