multiacc.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  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: multiacc.c
  7. *
  8. * Description:
  9. * This test creates multiple threads that accept on the
  10. * same listening socket.
  11. */
  12. #include "nspr.h"
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #define NUM_SERVER_THREADS 10
  17. static int num_server_threads = NUM_SERVER_THREADS;
  18. static PRThreadScope thread_scope = PR_GLOBAL_THREAD;
  19. static PRBool exit_flag = PR_FALSE;
  20. static void ServerThreadFunc(void *arg)
  21. {
  22. PRFileDesc *listenSock = (PRFileDesc *) arg;
  23. PRFileDesc *acceptSock;
  24. PRErrorCode err;
  25. PRStatus status;
  26. while (!exit_flag) {
  27. acceptSock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT);
  28. if (NULL == acceptSock) {
  29. err = PR_GetError();
  30. if (PR_PENDING_INTERRUPT_ERROR == err) {
  31. printf("server thread is interrupted\n");
  32. fflush(stdout);
  33. continue;
  34. }
  35. fprintf(stderr, "PR_Accept failed: %d\n", err);
  36. exit(1);
  37. }
  38. status = PR_Close(acceptSock);
  39. if (PR_FAILURE == status) {
  40. fprintf(stderr, "PR_Close failed\n");
  41. exit(1);
  42. }
  43. }
  44. }
  45. int main(int argc, char **argv)
  46. {
  47. PRNetAddr serverAddr;
  48. PRFileDesc *dummySock;
  49. PRFileDesc *listenSock;
  50. PRFileDesc *clientSock;
  51. PRThread *dummyThread;
  52. PRThread **serverThreads;
  53. PRStatus status;
  54. PRUint16 port;
  55. int idx;
  56. PRInt32 nbytes;
  57. char buf[1024];
  58. serverThreads = (PRThread **)
  59. PR_Malloc(num_server_threads * sizeof(PRThread *));
  60. if (NULL == serverThreads) {
  61. fprintf(stderr, "PR_Malloc failed\n");
  62. exit(1);
  63. }
  64. /*
  65. * Create a dummy listening socket and have the first
  66. * (dummy) thread listen on it. This is to ensure that
  67. * the first thread becomes the I/O continuation thread
  68. * in the pthreads implementation (see ptio.c) and remains
  69. * so throughout the test, so that we never have to
  70. * recycle the I/O continuation thread.
  71. */
  72. dummySock = PR_NewTCPSocket();
  73. if (NULL == dummySock) {
  74. fprintf(stderr, "PR_NewTCPSocket failed\n");
  75. exit(1);
  76. }
  77. memset(&serverAddr, 0, sizeof(serverAddr));
  78. status = PR_InitializeNetAddr(PR_IpAddrAny, 0, &serverAddr);
  79. if (PR_FAILURE == status) {
  80. fprintf(stderr, "PR_InitializeNetAddr failed\n");
  81. exit(1);
  82. }
  83. status = PR_Bind(dummySock, &serverAddr);
  84. if (PR_FAILURE == status) {
  85. fprintf(stderr, "PR_Bind failed\n");
  86. exit(1);
  87. }
  88. status = PR_Listen(dummySock, 5);
  89. if (PR_FAILURE == status) {
  90. fprintf(stderr, "PR_Listen failed\n");
  91. exit(1);
  92. }
  93. listenSock = PR_NewTCPSocket();
  94. if (NULL == listenSock) {
  95. fprintf(stderr, "PR_NewTCPSocket failed\n");
  96. exit(1);
  97. }
  98. memset(&serverAddr, 0, sizeof(serverAddr));
  99. status = PR_InitializeNetAddr(PR_IpAddrAny, 0, &serverAddr);
  100. if (PR_FAILURE == status) {
  101. fprintf(stderr, "PR_InitializeNetAddr failed\n");
  102. exit(1);
  103. }
  104. status = PR_Bind(listenSock, &serverAddr);
  105. if (PR_FAILURE == status) {
  106. fprintf(stderr, "PR_Bind failed\n");
  107. exit(1);
  108. }
  109. status = PR_GetSockName(listenSock, &serverAddr);
  110. if (PR_FAILURE == status) {
  111. fprintf(stderr, "PR_GetSockName failed\n");
  112. exit(1);
  113. }
  114. port = PR_ntohs(serverAddr.inet.port);
  115. status = PR_Listen(listenSock, 5);
  116. if (PR_FAILURE == status) {
  117. fprintf(stderr, "PR_Listen failed\n");
  118. exit(1);
  119. }
  120. printf("creating dummy thread\n");
  121. fflush(stdout);
  122. dummyThread = PR_CreateThread(PR_USER_THREAD,
  123. ServerThreadFunc, dummySock, PR_PRIORITY_NORMAL,
  124. thread_scope, PR_JOINABLE_THREAD, 0);
  125. if (NULL == dummyThread) {
  126. fprintf(stderr, "PR_CreateThread failed\n");
  127. exit(1);
  128. }
  129. printf("sleeping one second before creating server threads\n");
  130. fflush(stdout);
  131. PR_Sleep(PR_SecondsToInterval(1));
  132. for (idx = 0; idx < num_server_threads; idx++) {
  133. serverThreads[idx] = PR_CreateThread(PR_USER_THREAD,
  134. ServerThreadFunc, listenSock, PR_PRIORITY_NORMAL,
  135. thread_scope, PR_JOINABLE_THREAD, 0);
  136. if (NULL == serverThreads[idx]) {
  137. fprintf(stderr, "PR_CreateThread failed\n");
  138. exit(1);
  139. }
  140. }
  141. memset(&serverAddr, 0, sizeof(serverAddr));
  142. PR_InitializeNetAddr(PR_IpAddrLoopback, port, &serverAddr);
  143. clientSock = PR_NewTCPSocket();
  144. if (NULL == clientSock) {
  145. fprintf(stderr, "PR_NewTCPSocket failed\n");
  146. exit(1);
  147. }
  148. printf("sleeping one second before connecting\n");
  149. fflush(stdout);
  150. PR_Sleep(PR_SecondsToInterval(1));
  151. status = PR_Connect(clientSock, &serverAddr, PR_INTERVAL_NO_TIMEOUT);
  152. if (PR_FAILURE == status) {
  153. fprintf(stderr, "PR_Connect failed\n");
  154. exit(1);
  155. }
  156. nbytes = PR_Read(clientSock, buf, sizeof(buf));
  157. if (nbytes != 0) {
  158. fprintf(stderr, "expected 0 bytes but got %d bytes\n", nbytes);
  159. exit(1);
  160. }
  161. status = PR_Close(clientSock);
  162. if (PR_FAILURE == status) {
  163. fprintf(stderr, "PR_Close failed\n");
  164. exit(1);
  165. }
  166. printf("sleeping one second before shutting down server threads\n");
  167. fflush(stdout);
  168. PR_Sleep(PR_SecondsToInterval(1));
  169. exit_flag = PR_TRUE;
  170. status = PR_Interrupt(dummyThread);
  171. if (PR_FAILURE == status) {
  172. fprintf(stderr, "PR_Interrupt failed\n");
  173. exit(1);
  174. }
  175. status = PR_JoinThread(dummyThread);
  176. if (PR_FAILURE == status) {
  177. fprintf(stderr, "PR_JoinThread failed\n");
  178. exit(1);
  179. }
  180. for (idx = 0; idx < num_server_threads; idx++) {
  181. status = PR_Interrupt(serverThreads[idx]);
  182. if (PR_FAILURE == status) {
  183. fprintf(stderr, "PR_Interrupt failed\n");
  184. exit(1);
  185. }
  186. status = PR_JoinThread(serverThreads[idx]);
  187. if (PR_FAILURE == status) {
  188. fprintf(stderr, "PR_JoinThread failed\n");
  189. exit(1);
  190. }
  191. }
  192. PR_Free(serverThreads);
  193. status = PR_Close(dummySock);
  194. if (PR_FAILURE == status) {
  195. fprintf(stderr, "PR_Close failed\n");
  196. exit(1);
  197. }
  198. status = PR_Close(listenSock);
  199. if (PR_FAILURE == status) {
  200. fprintf(stderr, "PR_Close failed\n");
  201. exit(1);
  202. }
  203. printf("PASS\n");
  204. return 0;
  205. }