intrupt.c 9.5 KB

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