1
by Mike Hommey
Import upstream version 4.6.6 |
1 |
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
1.2.4
by Jamie Strandboge
Import upstream version 4.9.4 |
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/. */
|
|
1
by Mike Hommey
Import upstream version 4.6.6 |
5 |
|
6 |
/***********************************************************************
|
|
7 |
**
|
|
8 |
** Name: forktest.c
|
|
9 |
**
|
|
10 |
** Description: UNIX test for fork functions.
|
|
11 |
**
|
|
12 |
** Modification History:
|
|
13 |
** 15-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
|
|
14 |
** The debug mode will print all of the printfs associated with this test.
|
|
15 |
** The regress mode will be the default mode. Since the regress tool limits
|
|
16 |
** the output to a one line status:PASS or FAIL,all of the printf statements
|
|
17 |
** have been handled with an if (debug_mode) statement.
|
|
18 |
** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
|
|
19 |
** recognize the return code from tha main program.
|
|
20 |
** 12-June-97 AGarcic - Revert to return code 0 and 1, remove debug option (obsolete).
|
|
21 |
***********************************************************************/
|
|
22 |
||
23 |
/***********************************************************************
|
|
24 |
** Includes
|
|
25 |
***********************************************************************/
|
|
26 |
/* Used to get the command line option */
|
|
27 |
#include "plgetopt.h" |
|
28 |
||
29 |
#include "nspr.h" |
|
30 |
#include <string.h> |
|
31 |
#include <stdio.h> |
|
32 |
#include <stdlib.h> |
|
33 |
||
34 |
PRIntn failed_already=0; |
|
35 |
||
36 |
#ifdef XP_UNIX
|
|
37 |
||
38 |
#include <sys/types.h> |
|
39 |
#include <sys/wait.h> |
|
40 |
#include <unistd.h> |
|
41 |
#include <errno.h> |
|
42 |
||
43 |
static char *message = "Hello world!"; |
|
44 |
||
45 |
static void |
|
46 |
ClientThreadFunc(void *arg) |
|
47 |
{
|
|
48 |
PRNetAddr addr; |
|
49 |
PRFileDesc *sock = NULL; |
|
50 |
PRInt32 tmp = (PRInt32)arg; |
|
51 |
||
52 |
/*
|
|
53 |
* Make sure the PR_Accept call will block
|
|
54 |
*/
|
|
55 |
||
56 |
printf("Wait one second before connect\n"); |
|
57 |
fflush(stdout); |
|
58 |
PR_Sleep(PR_SecondsToInterval(1)); |
|
59 |
||
60 |
addr.inet.family = AF_INET; |
|
61 |
addr.inet.ip = PR_htonl(INADDR_ANY); |
|
62 |
addr.inet.port = 0; |
|
63 |
if ((sock = PR_NewTCPSocket()) == NULL) { |
|
64 |
fprintf(stderr, "failed to create TCP socket: error code %d\n", |
|
65 |
PR_GetError()); |
|
66 |
failed_already = 1; |
|
67 |
goto finish; |
|
68 |
}
|
|
69 |
if (PR_Bind(sock, &addr) != PR_SUCCESS) { |
|
70 |
fprintf(stderr, "PR_Bind failed: error code %d\n", |
|
71 |
PR_GetError()); |
|
72 |
failed_already = 1; |
|
73 |
goto finish; |
|
74 |
}
|
|
75 |
addr.inet.ip = PR_htonl(INADDR_LOOPBACK); |
|
76 |
addr.inet.port = PR_htons((PRInt16)tmp); |
|
77 |
printf("Connecting to port %hu\n", PR_ntohs(addr.inet.port)); |
|
78 |
fflush(stdout); |
|
79 |
if (PR_Connect(sock, &addr, PR_SecondsToInterval(5)) != |
|
80 |
PR_SUCCESS) { |
|
81 |
fprintf(stderr, "PR_Connect failed: error code %d\n", |
|
82 |
PR_GetError()); |
|
83 |
failed_already = 1; |
|
84 |
goto finish; |
|
85 |
}
|
|
86 |
printf("Writing message \"%s\"\n", message); |
|
87 |
fflush(stdout); |
|
88 |
if (PR_Send(sock, message, strlen(message) + 1, 0, PR_INTERVAL_NO_TIMEOUT) == |
|
89 |
-1) { |
|
90 |
fprintf(stderr, "PR_Send failed: error code %d\n", |
|
91 |
PR_GetError()); |
|
92 |
failed_already = 1; |
|
93 |
goto finish; |
|
94 |
}
|
|
95 |
finish: |
|
96 |
if (sock) { |
|
97 |
PR_Close(sock); |
|
98 |
}
|
|
99 |
return; |
|
100 |
}
|
|
101 |
||
102 |
/*
|
|
103 |
* DoIO --
|
|
104 |
* This function creates a thread that acts as a client and itself.
|
|
105 |
* acts as a server. Then it joins the client thread.
|
|
106 |
*/
|
|
107 |
static void |
|
108 |
DoIO(void) |
|
109 |
{
|
|
110 |
PRThread *clientThread; |
|
111 |
PRFileDesc *listenSock = NULL; |
|
112 |
PRFileDesc *sock = NULL; |
|
113 |
PRNetAddr addr; |
|
114 |
PRInt32 nBytes; |
|
115 |
char buf[128]; |
|
116 |
||
117 |
listenSock = PR_NewTCPSocket(); |
|
118 |
if (!listenSock) { |
|
119 |
fprintf(stderr, "failed to create a TCP socket: error code %d\n", |
|
120 |
PR_GetError()); |
|
121 |
failed_already = 1; |
|
122 |
goto finish; |
|
123 |
}
|
|
124 |
addr.inet.family = AF_INET; |
|
125 |
addr.inet.ip = PR_htonl(INADDR_ANY); |
|
126 |
addr.inet.port = 0; |
|
127 |
if (PR_Bind(listenSock, &addr) == PR_FAILURE) { |
|
128 |
fprintf(stderr, "failed to bind socket: error code %d\n", |
|
129 |
PR_GetError()); |
|
130 |
failed_already = 1; |
|
131 |
goto finish; |
|
132 |
}
|
|
133 |
if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) { |
|
134 |
fprintf(stderr, "failed to get socket port number: error code %d\n", |
|
135 |
PR_GetError()); |
|
136 |
failed_already = 1; |
|
137 |
goto finish; |
|
138 |
}
|
|
139 |
if (PR_Listen(listenSock, 5) == PR_FAILURE) { |
|
140 |
fprintf(stderr, "PR_Listen failed: error code %d\n", |
|
141 |
PR_GetError()); |
|
142 |
failed_already = 1; |
|
143 |
goto finish; |
|
144 |
}
|
|
145 |
clientThread = PR_CreateThread( PR_USER_THREAD, ClientThreadFunc, |
|
146 |
(void *) PR_ntohs(addr.inet.port), PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, |
|
147 |
PR_JOINABLE_THREAD, 0); |
|
148 |
if (clientThread == NULL) { |
|
149 |
fprintf(stderr, "Cannot create client thread: (%d, %d)\n", |
|
150 |
PR_GetError(), PR_GetOSError()); |
|
151 |
failed_already = 1; |
|
152 |
goto finish; |
|
153 |
}
|
|
154 |
printf("Accepting connection at port %hu\n", PR_ntohs(addr.inet.port)); |
|
155 |
fflush(stdout); |
|
156 |
sock = PR_Accept(listenSock, &addr, PR_SecondsToInterval(5)); |
|
157 |
if (!sock) { |
|
158 |
fprintf(stderr, "PR_Accept failed: error code %d\n", |
|
159 |
PR_GetError()); |
|
160 |
failed_already = 1; |
|
161 |
goto finish; |
|
162 |
}
|
|
163 |
nBytes = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT); |
|
164 |
if (nBytes == -1) { |
|
165 |
fprintf(stderr, "PR_Recv failed: error code %d\n", |
|
166 |
PR_GetError()); |
|
167 |
failed_already = 1; |
|
168 |
goto finish; |
|
169 |
}
|
|
170 |
||
171 |
/*
|
|
172 |
* Make sure it has proper null byte to mark end of string
|
|
173 |
*/
|
|
174 |
||
175 |
buf[sizeof(buf) - 1] = '\0'; |
|
176 |
printf("Received \"%s\" from the client\n", buf); |
|
177 |
fflush(stdout); |
|
178 |
if (!strcmp(buf, message)) { |
|
179 |
PR_JoinThread(clientThread); |
|
180 |
||
181 |
printf("The message is received correctly\n"); |
|
182 |
fflush(stdout); |
|
183 |
} else { |
|
184 |
fprintf(stderr, "The message should be \"%s\"\n", |
|
185 |
message); |
|
186 |
failed_already = 1; |
|
187 |
}
|
|
188 |
||
189 |
finish: |
|
190 |
if (listenSock) { |
|
191 |
PR_Close(listenSock); |
|
192 |
}
|
|
193 |
if (sock) { |
|
194 |
PR_Close(sock); |
|
195 |
}
|
|
196 |
return; |
|
197 |
}
|
|
198 |
||
199 |
#ifdef _PR_DCETHREADS
|
|
200 |
||
201 |
#include <syscall.h> |
|
202 |
||
203 |
pid_t PR_UnixFork1(void) |
|
204 |
{
|
|
205 |
pid_t parent = getpid(); |
|
206 |
int rv = syscall(SYS_fork); |
|
207 |
||
208 |
if (rv == -1) { |
|
209 |
return (pid_t) -1; |
|
210 |
} else { |
|
211 |
/* For each process, rv is the pid of the other process */
|
|
212 |
if (rv == parent) { |
|
213 |
/* the child */
|
|
214 |
return 0; |
|
215 |
} else { |
|
216 |
/* the parent */
|
|
217 |
return rv; |
|
218 |
}
|
|
219 |
}
|
|
220 |
}
|
|
221 |
||
222 |
#elif defined(SOLARIS)
|
|
223 |
||
224 |
/*
|
|
225 |
* It seems like that in Solaris 2.4 one must call fork1() if the
|
|
226 |
* the child process is going to use thread functions. Solaris 2.5
|
|
227 |
* doesn't have this problem. Calling fork() also works.
|
|
228 |
*/
|
|
229 |
||
230 |
pid_t PR_UnixFork1(void) |
|
231 |
{
|
|
232 |
return fork1(); |
|
233 |
}
|
|
234 |
||
235 |
#else
|
|
236 |
||
237 |
pid_t PR_UnixFork1(void) |
|
238 |
{
|
|
239 |
return fork(); |
|
240 |
}
|
|
241 |
||
242 |
#endif /* PR_DCETHREADS */ |
|
243 |
||
1.1.10
by Alexander Sack
Import upstream version 4.8 |
244 |
int main(int argc, char **argv) |
1
by Mike Hommey
Import upstream version 4.6.6 |
245 |
{
|
246 |
pid_t pid; |
|
247 |
int rv; |
|
248 |
||
249 |
/* main test program */
|
|
250 |
||
251 |
DoIO(); |
|
252 |
||
253 |
pid = PR_UnixFork1(); |
|
254 |
||
255 |
if (pid == (pid_t) -1) { |
|
256 |
fprintf(stderr, "Fork failed: errno %d\n", errno); |
|
257 |
failed_already=1; |
|
258 |
return 1; |
|
259 |
} else if (pid > 0) { |
|
260 |
int childStatus; |
|
261 |
||
262 |
printf("Fork succeeded. Parent process continues.\n"); |
|
263 |
DoIO(); |
|
264 |
if ((rv = waitpid(pid, &childStatus, 0)) != pid) { |
|
265 |
#if defined(IRIX) && !defined(_PR_PTHREADS)
|
|
266 |
/*
|
|
267 |
* nspr may handle SIGCLD signal
|
|
268 |
*/
|
|
269 |
if ((rv < 0) && (errno == ECHILD)) { |
|
270 |
} else |
|
271 |
#endif
|
|
272 |
{
|
|
273 |
fprintf(stderr, "waitpid failed: %d\n", errno); |
|
274 |
failed_already = 1; |
|
275 |
}
|
|
276 |
} else if (!WIFEXITED(childStatus) |
|
277 |
|| WEXITSTATUS(childStatus) != 0) { |
|
278 |
failed_already = 1; |
|
279 |
}
|
|
280 |
printf("Parent process exits.\n"); |
|
281 |
if (!failed_already) { |
|
282 |
printf("PASSED\n"); |
|
283 |
} else { |
|
284 |
printf("FAILED\n"); |
|
285 |
}
|
|
286 |
return failed_already; |
|
287 |
} else { |
|
288 |
#if defined(IRIX) && !defined(_PR_PTHREADS)
|
|
289 |
extern void _PR_IRIX_CHILD_PROCESS(void); |
|
290 |
_PR_IRIX_CHILD_PROCESS(); |
|
291 |
#endif
|
|
292 |
printf("Fork succeeded. Child process continues.\n"); |
|
293 |
DoIO(); |
|
294 |
printf("Child process exits.\n"); |
|
295 |
return failed_already; |
|
296 |
}
|
|
297 |
}
|
|
298 |
||
299 |
#else /* XP_UNIX */ |
|
300 |
||
301 |
int main( int argc, |
|
302 |
char *argv[] |
|
303 |
)
|
|
304 |
{
|
|
305 |
||
306 |
printf("The fork test is applicable to Unix only.\n"); |
|
307 |
return 0; |
|
308 |
||
309 |
}
|
|
310 |
||
311 |
#endif /* XP_UNIX */ |