1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/tests/forktest.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,311 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/*********************************************************************** 1.10 +** 1.11 +** Name: forktest.c 1.12 +** 1.13 +** Description: UNIX test for fork functions. 1.14 +** 1.15 +** Modification History: 1.16 +** 15-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. 1.17 +** The debug mode will print all of the printfs associated with this test. 1.18 +** The regress mode will be the default mode. Since the regress tool limits 1.19 +** the output to a one line status:PASS or FAIL,all of the printf statements 1.20 +** have been handled with an if (debug_mode) statement. 1.21 +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to 1.22 +** recognize the return code from tha main program. 1.23 +** 12-June-97 AGarcic - Revert to return code 0 and 1, remove debug option (obsolete). 1.24 +***********************************************************************/ 1.25 + 1.26 +/*********************************************************************** 1.27 +** Includes 1.28 +***********************************************************************/ 1.29 +/* Used to get the command line option */ 1.30 +#include "plgetopt.h" 1.31 + 1.32 +#include "nspr.h" 1.33 +#include <string.h> 1.34 +#include <stdio.h> 1.35 +#include <stdlib.h> 1.36 + 1.37 +PRIntn failed_already=0; 1.38 + 1.39 +#ifdef XP_UNIX 1.40 + 1.41 +#include <sys/types.h> 1.42 +#include <sys/wait.h> 1.43 +#include <unistd.h> 1.44 +#include <errno.h> 1.45 + 1.46 +static char *message = "Hello world!"; 1.47 + 1.48 +static void 1.49 +ClientThreadFunc(void *arg) 1.50 +{ 1.51 + PRNetAddr addr; 1.52 + PRFileDesc *sock = NULL; 1.53 + PRInt32 tmp = (PRInt32)arg; 1.54 + 1.55 + /* 1.56 + * Make sure the PR_Accept call will block 1.57 + */ 1.58 + 1.59 + printf("Wait one second before connect\n"); 1.60 + fflush(stdout); 1.61 + PR_Sleep(PR_SecondsToInterval(1)); 1.62 + 1.63 + addr.inet.family = AF_INET; 1.64 + addr.inet.ip = PR_htonl(INADDR_ANY); 1.65 + addr.inet.port = 0; 1.66 + if ((sock = PR_NewTCPSocket()) == NULL) { 1.67 + fprintf(stderr, "failed to create TCP socket: error code %d\n", 1.68 + PR_GetError()); 1.69 + failed_already = 1; 1.70 + goto finish; 1.71 + } 1.72 + if (PR_Bind(sock, &addr) != PR_SUCCESS) { 1.73 + fprintf(stderr, "PR_Bind failed: error code %d\n", 1.74 + PR_GetError()); 1.75 + failed_already = 1; 1.76 + goto finish; 1.77 + } 1.78 + addr.inet.ip = PR_htonl(INADDR_LOOPBACK); 1.79 + addr.inet.port = PR_htons((PRInt16)tmp); 1.80 + printf("Connecting to port %hu\n", PR_ntohs(addr.inet.port)); 1.81 + fflush(stdout); 1.82 + if (PR_Connect(sock, &addr, PR_SecondsToInterval(5)) != 1.83 + PR_SUCCESS) { 1.84 + fprintf(stderr, "PR_Connect failed: error code %d\n", 1.85 + PR_GetError()); 1.86 + failed_already = 1; 1.87 + goto finish; 1.88 + } 1.89 + printf("Writing message \"%s\"\n", message); 1.90 + fflush(stdout); 1.91 + if (PR_Send(sock, message, strlen(message) + 1, 0, PR_INTERVAL_NO_TIMEOUT) == 1.92 + -1) { 1.93 + fprintf(stderr, "PR_Send failed: error code %d\n", 1.94 + PR_GetError()); 1.95 + failed_already = 1; 1.96 + goto finish; 1.97 + } 1.98 +finish: 1.99 + if (sock) { 1.100 + PR_Close(sock); 1.101 + } 1.102 + return; 1.103 +} 1.104 + 1.105 +/* 1.106 + * DoIO -- 1.107 + * This function creates a thread that acts as a client and itself. 1.108 + * acts as a server. Then it joins the client thread. 1.109 + */ 1.110 +static void 1.111 +DoIO(void) 1.112 +{ 1.113 + PRThread *clientThread; 1.114 + PRFileDesc *listenSock = NULL; 1.115 + PRFileDesc *sock = NULL; 1.116 + PRNetAddr addr; 1.117 + PRInt32 nBytes; 1.118 + char buf[128]; 1.119 + 1.120 + listenSock = PR_NewTCPSocket(); 1.121 + if (!listenSock) { 1.122 + fprintf(stderr, "failed to create a TCP socket: error code %d\n", 1.123 + PR_GetError()); 1.124 + failed_already = 1; 1.125 + goto finish; 1.126 + } 1.127 + addr.inet.family = AF_INET; 1.128 + addr.inet.ip = PR_htonl(INADDR_ANY); 1.129 + addr.inet.port = 0; 1.130 + if (PR_Bind(listenSock, &addr) == PR_FAILURE) { 1.131 + fprintf(stderr, "failed to bind socket: error code %d\n", 1.132 + PR_GetError()); 1.133 + failed_already = 1; 1.134 + goto finish; 1.135 + } 1.136 + if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) { 1.137 + fprintf(stderr, "failed to get socket port number: error code %d\n", 1.138 + PR_GetError()); 1.139 + failed_already = 1; 1.140 + goto finish; 1.141 + } 1.142 + if (PR_Listen(listenSock, 5) == PR_FAILURE) { 1.143 + fprintf(stderr, "PR_Listen failed: error code %d\n", 1.144 + PR_GetError()); 1.145 + failed_already = 1; 1.146 + goto finish; 1.147 + } 1.148 + clientThread = PR_CreateThread( PR_USER_THREAD, ClientThreadFunc, 1.149 + (void *) PR_ntohs(addr.inet.port), PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, 1.150 + PR_JOINABLE_THREAD, 0); 1.151 + if (clientThread == NULL) { 1.152 + fprintf(stderr, "Cannot create client thread: (%d, %d)\n", 1.153 + PR_GetError(), PR_GetOSError()); 1.154 + failed_already = 1; 1.155 + goto finish; 1.156 + } 1.157 + printf("Accepting connection at port %hu\n", PR_ntohs(addr.inet.port)); 1.158 + fflush(stdout); 1.159 + sock = PR_Accept(listenSock, &addr, PR_SecondsToInterval(5)); 1.160 + if (!sock) { 1.161 + fprintf(stderr, "PR_Accept failed: error code %d\n", 1.162 + PR_GetError()); 1.163 + failed_already = 1; 1.164 + goto finish; 1.165 + } 1.166 + nBytes = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT); 1.167 + if (nBytes == -1) { 1.168 + fprintf(stderr, "PR_Recv failed: error code %d\n", 1.169 + PR_GetError()); 1.170 + failed_already = 1; 1.171 + goto finish; 1.172 + } 1.173 + 1.174 + /* 1.175 + * Make sure it has proper null byte to mark end of string 1.176 + */ 1.177 + 1.178 + buf[sizeof(buf) - 1] = '\0'; 1.179 + printf("Received \"%s\" from the client\n", buf); 1.180 + fflush(stdout); 1.181 + if (!strcmp(buf, message)) { 1.182 + PR_JoinThread(clientThread); 1.183 + 1.184 + printf("The message is received correctly\n"); 1.185 + fflush(stdout); 1.186 + } else { 1.187 + fprintf(stderr, "The message should be \"%s\"\n", 1.188 + message); 1.189 + failed_already = 1; 1.190 + } 1.191 + 1.192 +finish: 1.193 + if (listenSock) { 1.194 + PR_Close(listenSock); 1.195 + } 1.196 + if (sock) { 1.197 + PR_Close(sock); 1.198 + } 1.199 + return; 1.200 +} 1.201 + 1.202 +#ifdef _PR_DCETHREADS 1.203 + 1.204 +#include <syscall.h> 1.205 + 1.206 +pid_t PR_UnixFork1(void) 1.207 +{ 1.208 + pid_t parent = getpid(); 1.209 + int rv = syscall(SYS_fork); 1.210 + 1.211 + if (rv == -1) { 1.212 + return (pid_t) -1; 1.213 + } else { 1.214 + /* For each process, rv is the pid of the other process */ 1.215 + if (rv == parent) { 1.216 + /* the child */ 1.217 + return 0; 1.218 + } else { 1.219 + /* the parent */ 1.220 + return rv; 1.221 + } 1.222 + } 1.223 +} 1.224 + 1.225 +#elif defined(SOLARIS) 1.226 + 1.227 +/* 1.228 + * It seems like that in Solaris 2.4 one must call fork1() if the 1.229 + * the child process is going to use thread functions. Solaris 2.5 1.230 + * doesn't have this problem. Calling fork() also works. 1.231 + */ 1.232 + 1.233 +pid_t PR_UnixFork1(void) 1.234 +{ 1.235 + return fork1(); 1.236 +} 1.237 + 1.238 +#else 1.239 + 1.240 +pid_t PR_UnixFork1(void) 1.241 +{ 1.242 + return fork(); 1.243 +} 1.244 + 1.245 +#endif /* PR_DCETHREADS */ 1.246 + 1.247 +int main(int argc, char **argv) 1.248 +{ 1.249 + pid_t pid; 1.250 + int rv; 1.251 + 1.252 + /* main test program */ 1.253 + 1.254 + DoIO(); 1.255 + 1.256 + pid = PR_UnixFork1(); 1.257 + 1.258 + if (pid == (pid_t) -1) { 1.259 + fprintf(stderr, "Fork failed: errno %d\n", errno); 1.260 + failed_already=1; 1.261 + return 1; 1.262 + } else if (pid > 0) { 1.263 + int childStatus; 1.264 + 1.265 + printf("Fork succeeded. Parent process continues.\n"); 1.266 + DoIO(); 1.267 + if ((rv = waitpid(pid, &childStatus, 0)) != pid) { 1.268 +#if defined(IRIX) && !defined(_PR_PTHREADS) 1.269 + /* 1.270 + * nspr may handle SIGCLD signal 1.271 + */ 1.272 + if ((rv < 0) && (errno == ECHILD)) { 1.273 + } else 1.274 +#endif 1.275 + { 1.276 + fprintf(stderr, "waitpid failed: %d\n", errno); 1.277 + failed_already = 1; 1.278 + } 1.279 + } else if (!WIFEXITED(childStatus) 1.280 + || WEXITSTATUS(childStatus) != 0) { 1.281 + failed_already = 1; 1.282 + } 1.283 + printf("Parent process exits.\n"); 1.284 + if (!failed_already) { 1.285 + printf("PASSED\n"); 1.286 + } else { 1.287 + printf("FAILED\n"); 1.288 + } 1.289 + return failed_already; 1.290 + } else { 1.291 +#if defined(IRIX) && !defined(_PR_PTHREADS) 1.292 + extern void _PR_IRIX_CHILD_PROCESS(void); 1.293 + _PR_IRIX_CHILD_PROCESS(); 1.294 +#endif 1.295 + printf("Fork succeeded. Child process continues.\n"); 1.296 + DoIO(); 1.297 + printf("Child process exits.\n"); 1.298 + return failed_already; 1.299 + } 1.300 +} 1.301 + 1.302 +#else /* XP_UNIX */ 1.303 + 1.304 +int main( int argc, 1.305 +char *argv[] 1.306 +) 1.307 +{ 1.308 + 1.309 + printf("The fork test is applicable to Unix only.\n"); 1.310 + return 0; 1.311 + 1.312 +} 1.313 + 1.314 +#endif /* XP_UNIX */