ioconthr.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  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. * This is a test for the io continuation thread machinery
  7. * in pthreads.
  8. */
  9. #include "nspr.h"
  10. #include <stdio.h>
  11. int num_threads = 10; /* must be an even number */
  12. PRThreadScope thread_scope = PR_GLOBAL_THREAD;
  13. void ThreadFunc(void *arg)
  14. {
  15. PRFileDesc *fd = (PRFileDesc *) arg;
  16. char buf[1024];
  17. PRInt32 nbytes;
  18. PRErrorCode err;
  19. nbytes = PR_Recv(fd, buf, sizeof(buf), 0, PR_SecondsToInterval(20));
  20. if (nbytes == -1) {
  21. err = PR_GetError();
  22. if (err != PR_PENDING_INTERRUPT_ERROR) {
  23. fprintf(stderr, "PR_Recv failed: (%d, %d)\n",
  24. err, PR_GetOSError());
  25. PR_ProcessExit(1);
  26. }
  27. /*
  28. * After getting an I/O interrupt, this thread must
  29. * close the fd before it exits due to a limitation
  30. * of our NT implementation.
  31. */
  32. if (PR_Close(fd) == PR_FAILURE) {
  33. fprintf(stderr, "PR_Close failed\n");
  34. PR_ProcessExit(1);
  35. }
  36. } else {
  37. fprintf(stderr, "PR_Recv received %d bytes!?\n", nbytes);
  38. PR_ProcessExit(1);
  39. }
  40. }
  41. int main(int argc, char **argv)
  42. {
  43. PRFileDesc **fds;
  44. PRThread **threads;
  45. PRIntervalTime start, elapsed;
  46. int index;
  47. fds = (PRFileDesc **) PR_MALLOC(2 * num_threads * sizeof(PRFileDesc *));
  48. PR_ASSERT(fds != NULL);
  49. threads = (PRThread **) PR_MALLOC(num_threads * sizeof(PRThread *));
  50. PR_ASSERT(threads != NULL);
  51. for (index = 0; index < num_threads; index++) {
  52. if (PR_NewTCPSocketPair(&fds[2 * index]) == PR_FAILURE) {
  53. fprintf(stderr, "PR_NewTCPSocket failed\n");
  54. PR_ProcessExit(1);
  55. }
  56. threads[index] = PR_CreateThread(
  57. PR_USER_THREAD, ThreadFunc, fds[2 * index],
  58. PR_PRIORITY_NORMAL, thread_scope, PR_JOINABLE_THREAD, 0);
  59. if (NULL == threads[index]) {
  60. fprintf(stderr, "PR_CreateThread failed\n");
  61. PR_ProcessExit(1);
  62. }
  63. }
  64. /* Let the threads block in PR_Recv */
  65. PR_Sleep(PR_SecondsToInterval(2));
  66. printf("Interrupting the threads\n");
  67. fflush(stdout);
  68. start = PR_IntervalNow();
  69. for (index = 0; index < num_threads; index++) {
  70. if (PR_Interrupt(threads[index]) == PR_FAILURE) {
  71. fprintf(stderr, "PR_Interrupt failed\n");
  72. PR_ProcessExit(1);
  73. }
  74. }
  75. for (index = 0; index < num_threads; index++) {
  76. if (PR_JoinThread(threads[index]) == PR_FAILURE) {
  77. fprintf(stderr, "PR_JoinThread failed\n");
  78. PR_ProcessExit(1);
  79. }
  80. }
  81. elapsed = (PRIntervalTime)(PR_IntervalNow() - start);
  82. printf("Threads terminated in %d milliseconds\n",
  83. PR_IntervalToMilliseconds(elapsed));
  84. fflush(stdout);
  85. /* We are being very generous and allow 10 seconds. */
  86. if (elapsed >= PR_SecondsToInterval(10)) {
  87. fprintf(stderr, "Interrupting threads took longer than 10 seconds!!\n");
  88. PR_ProcessExit(1);
  89. }
  90. for (index = 0; index < num_threads; index++) {
  91. /* fds[2 * index] was passed to and closed by threads[index]. */
  92. if (PR_Close(fds[2 * index + 1]) == PR_FAILURE) {
  93. fprintf(stderr, "PR_Close failed\n");
  94. PR_ProcessExit(1);
  95. }
  96. }
  97. PR_DELETE(threads);
  98. PR_DELETE(fds);
  99. printf("PASS\n");
  100. PR_Cleanup();
  101. return 0;
  102. }