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