xref: /netbsd/external/mit/libuv/dist/test/test-fork.c (revision fbb2e0a3)
1*fbb2e0a3Schristos /* Copyright libuv project contributors. All rights reserved.
2*fbb2e0a3Schristos  *
3*fbb2e0a3Schristos  * Permission is hereby granted, free of charge, to any person obtaining a copy
4*fbb2e0a3Schristos  * of this software and associated documentation files (the "Software"), to
5*fbb2e0a3Schristos  * deal in the Software without restriction, including without limitation the
6*fbb2e0a3Schristos  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7*fbb2e0a3Schristos  * sell copies of the Software, and to permit persons to whom the Software is
8*fbb2e0a3Schristos  * furnished to do so, subject to the following conditions:
9*fbb2e0a3Schristos  *
10*fbb2e0a3Schristos  * The above copyright notice and this permission notice shall be included in
11*fbb2e0a3Schristos  * all copies or substantial portions of the Software.
12*fbb2e0a3Schristos  *
13*fbb2e0a3Schristos  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14*fbb2e0a3Schristos  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15*fbb2e0a3Schristos  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16*fbb2e0a3Schristos  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17*fbb2e0a3Schristos  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18*fbb2e0a3Schristos  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19*fbb2e0a3Schristos  * IN THE SOFTWARE.
20*fbb2e0a3Schristos  */
21*fbb2e0a3Schristos 
22*fbb2e0a3Schristos /* These tests are Unix only. */
23*fbb2e0a3Schristos #ifndef _WIN32
24*fbb2e0a3Schristos 
25*fbb2e0a3Schristos #include <unistd.h>
26*fbb2e0a3Schristos #include <sys/wait.h>
27*fbb2e0a3Schristos #include <sys/socket.h>
28*fbb2e0a3Schristos #include <string.h>
29*fbb2e0a3Schristos 
30*fbb2e0a3Schristos #include "uv.h"
31*fbb2e0a3Schristos #include "task.h"
32*fbb2e0a3Schristos 
33*fbb2e0a3Schristos static int timer_cb_called;
34*fbb2e0a3Schristos static int socket_cb_called;
35*fbb2e0a3Schristos 
timer_cb(uv_timer_t * timer)36*fbb2e0a3Schristos static void timer_cb(uv_timer_t* timer) {
37*fbb2e0a3Schristos   timer_cb_called++;
38*fbb2e0a3Schristos   uv_close((uv_handle_t*) timer, NULL);
39*fbb2e0a3Schristos }
40*fbb2e0a3Schristos 
41*fbb2e0a3Schristos 
42*fbb2e0a3Schristos static int socket_cb_read_fd;
43*fbb2e0a3Schristos static int socket_cb_read_size;
44*fbb2e0a3Schristos static char socket_cb_read_buf[1024];
45*fbb2e0a3Schristos 
46*fbb2e0a3Schristos 
socket_cb(uv_poll_t * poll,int status,int events)47*fbb2e0a3Schristos static void socket_cb(uv_poll_t* poll, int status, int events) {
48*fbb2e0a3Schristos   ssize_t cnt;
49*fbb2e0a3Schristos   socket_cb_called++;
50*fbb2e0a3Schristos   ASSERT(0 == status);
51*fbb2e0a3Schristos   printf("Socket cb got events %d\n", events);
52*fbb2e0a3Schristos   ASSERT(UV_READABLE == (events & UV_READABLE));
53*fbb2e0a3Schristos   if (socket_cb_read_fd) {
54*fbb2e0a3Schristos     cnt = read(socket_cb_read_fd, socket_cb_read_buf, socket_cb_read_size);
55*fbb2e0a3Schristos     ASSERT(cnt == socket_cb_read_size);
56*fbb2e0a3Schristos   }
57*fbb2e0a3Schristos   uv_close((uv_handle_t*) poll, NULL);
58*fbb2e0a3Schristos }
59*fbb2e0a3Schristos 
60*fbb2e0a3Schristos 
run_timer_loop_once(void)61*fbb2e0a3Schristos static void run_timer_loop_once(void) {
62*fbb2e0a3Schristos   uv_loop_t* loop;
63*fbb2e0a3Schristos   uv_timer_t timer_handle;
64*fbb2e0a3Schristos 
65*fbb2e0a3Schristos   loop = uv_default_loop();
66*fbb2e0a3Schristos 
67*fbb2e0a3Schristos   timer_cb_called = 0; /* Reset for the child. */
68*fbb2e0a3Schristos 
69*fbb2e0a3Schristos   ASSERT(0 == uv_timer_init(loop, &timer_handle));
70*fbb2e0a3Schristos   ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 1, 0));
71*fbb2e0a3Schristos   ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
72*fbb2e0a3Schristos   ASSERT(1 == timer_cb_called);
73*fbb2e0a3Schristos }
74*fbb2e0a3Schristos 
75*fbb2e0a3Schristos 
assert_wait_child(pid_t child_pid)76*fbb2e0a3Schristos static void assert_wait_child(pid_t child_pid) {
77*fbb2e0a3Schristos   pid_t waited_pid;
78*fbb2e0a3Schristos   int child_stat;
79*fbb2e0a3Schristos 
80*fbb2e0a3Schristos   waited_pid = waitpid(child_pid, &child_stat, 0);
81*fbb2e0a3Schristos   printf("Waited pid is %d with status %d\n", waited_pid, child_stat);
82*fbb2e0a3Schristos   if (waited_pid == -1) {
83*fbb2e0a3Schristos     perror("Failed to wait");
84*fbb2e0a3Schristos   }
85*fbb2e0a3Schristos   ASSERT(child_pid == waited_pid);
86*fbb2e0a3Schristos   ASSERT(WIFEXITED(child_stat)); /* Clean exit, not a signal. */
87*fbb2e0a3Schristos   ASSERT(!WIFSIGNALED(child_stat));
88*fbb2e0a3Schristos   ASSERT(0 == WEXITSTATUS(child_stat));
89*fbb2e0a3Schristos }
90*fbb2e0a3Schristos 
91*fbb2e0a3Schristos 
TEST_IMPL(fork_timer)92*fbb2e0a3Schristos TEST_IMPL(fork_timer) {
93*fbb2e0a3Schristos   /* Timers continue to work after we fork. */
94*fbb2e0a3Schristos 
95*fbb2e0a3Schristos   /*
96*fbb2e0a3Schristos    * Establish the loop before we fork to make sure that it
97*fbb2e0a3Schristos    * has state to get reset after the fork.
98*fbb2e0a3Schristos    */
99*fbb2e0a3Schristos   pid_t child_pid;
100*fbb2e0a3Schristos 
101*fbb2e0a3Schristos   run_timer_loop_once();
102*fbb2e0a3Schristos   child_pid = fork();
103*fbb2e0a3Schristos   ASSERT(child_pid != -1);
104*fbb2e0a3Schristos 
105*fbb2e0a3Schristos   if (child_pid != 0) {
106*fbb2e0a3Schristos     /* parent */
107*fbb2e0a3Schristos     assert_wait_child(child_pid);
108*fbb2e0a3Schristos   } else {
109*fbb2e0a3Schristos     /* child */
110*fbb2e0a3Schristos     ASSERT(0 == uv_loop_fork(uv_default_loop()));
111*fbb2e0a3Schristos     run_timer_loop_once();
112*fbb2e0a3Schristos   }
113*fbb2e0a3Schristos 
114*fbb2e0a3Schristos   MAKE_VALGRIND_HAPPY();
115*fbb2e0a3Schristos   return 0;
116*fbb2e0a3Schristos }
117*fbb2e0a3Schristos 
118*fbb2e0a3Schristos 
TEST_IMPL(fork_socketpair)119*fbb2e0a3Schristos TEST_IMPL(fork_socketpair) {
120*fbb2e0a3Schristos   /* A socket opened in the parent and accept'd in the
121*fbb2e0a3Schristos      child works after a fork. */
122*fbb2e0a3Schristos   pid_t child_pid;
123*fbb2e0a3Schristos   int socket_fds[2];
124*fbb2e0a3Schristos   uv_poll_t poll_handle;
125*fbb2e0a3Schristos 
126*fbb2e0a3Schristos   /* Prime the loop. */
127*fbb2e0a3Schristos   run_timer_loop_once();
128*fbb2e0a3Schristos 
129*fbb2e0a3Schristos   ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds));
130*fbb2e0a3Schristos 
131*fbb2e0a3Schristos   /* Create the server watcher in the parent, use it in the child. */
132*fbb2e0a3Schristos   ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, socket_fds[0]));
133*fbb2e0a3Schristos 
134*fbb2e0a3Schristos   child_pid = fork();
135*fbb2e0a3Schristos   ASSERT(child_pid != -1);
136*fbb2e0a3Schristos 
137*fbb2e0a3Schristos   if (child_pid != 0) {
138*fbb2e0a3Schristos     /* parent */
139*fbb2e0a3Schristos     ASSERT(3 == send(socket_fds[1], "hi\n", 3, 0));
140*fbb2e0a3Schristos     assert_wait_child(child_pid);
141*fbb2e0a3Schristos   } else {
142*fbb2e0a3Schristos     /* child */
143*fbb2e0a3Schristos     ASSERT(0 == uv_loop_fork(uv_default_loop()));
144*fbb2e0a3Schristos     ASSERT(0 == socket_cb_called);
145*fbb2e0a3Schristos     ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, socket_cb));
146*fbb2e0a3Schristos     printf("Going to run the loop in the child\n");
147*fbb2e0a3Schristos     ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
148*fbb2e0a3Schristos     ASSERT(1 == socket_cb_called);
149*fbb2e0a3Schristos   }
150*fbb2e0a3Schristos 
151*fbb2e0a3Schristos   MAKE_VALGRIND_HAPPY();
152*fbb2e0a3Schristos   return 0;
153*fbb2e0a3Schristos }
154*fbb2e0a3Schristos 
155*fbb2e0a3Schristos 
TEST_IMPL(fork_socketpair_started)156*fbb2e0a3Schristos TEST_IMPL(fork_socketpair_started) {
157*fbb2e0a3Schristos   /* A socket opened in the parent and accept'd in the
158*fbb2e0a3Schristos      child works after a fork, even if the watcher was already
159*fbb2e0a3Schristos      started, and then stopped in the parent. */
160*fbb2e0a3Schristos   pid_t child_pid;
161*fbb2e0a3Schristos   int socket_fds[2];
162*fbb2e0a3Schristos   int sync_pipe[2];
163*fbb2e0a3Schristos   char sync_buf[1];
164*fbb2e0a3Schristos   uv_poll_t poll_handle;
165*fbb2e0a3Schristos 
166*fbb2e0a3Schristos   ASSERT(0 == pipe(sync_pipe));
167*fbb2e0a3Schristos 
168*fbb2e0a3Schristos   /* Prime the loop. */
169*fbb2e0a3Schristos   run_timer_loop_once();
170*fbb2e0a3Schristos 
171*fbb2e0a3Schristos   ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds));
172*fbb2e0a3Schristos 
173*fbb2e0a3Schristos   /* Create and start the server watcher in the parent, use it in the child. */
174*fbb2e0a3Schristos   ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, socket_fds[0]));
175*fbb2e0a3Schristos   ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, socket_cb));
176*fbb2e0a3Schristos 
177*fbb2e0a3Schristos   /* Run the loop AFTER the poll watcher is registered to make sure it
178*fbb2e0a3Schristos      gets passed to the kernel. Use NOWAIT and expect a non-zero
179*fbb2e0a3Schristos      return to prove the poll watcher is active.
180*fbb2e0a3Schristos   */
181*fbb2e0a3Schristos   ASSERT(1 == uv_run(uv_default_loop(), UV_RUN_NOWAIT));
182*fbb2e0a3Schristos 
183*fbb2e0a3Schristos   child_pid = fork();
184*fbb2e0a3Schristos   ASSERT(child_pid != -1);
185*fbb2e0a3Schristos 
186*fbb2e0a3Schristos   if (child_pid != 0) {
187*fbb2e0a3Schristos     /* parent */
188*fbb2e0a3Schristos     ASSERT(0 == uv_poll_stop(&poll_handle));
189*fbb2e0a3Schristos     uv_close((uv_handle_t*)&poll_handle, NULL);
190*fbb2e0a3Schristos     ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
191*fbb2e0a3Schristos     ASSERT(0 == socket_cb_called);
192*fbb2e0a3Schristos     ASSERT(1 == write(sync_pipe[1], "1", 1)); /* alert child */
193*fbb2e0a3Schristos     ASSERT(3 == send(socket_fds[1], "hi\n", 3, 0));
194*fbb2e0a3Schristos 
195*fbb2e0a3Schristos     ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
196*fbb2e0a3Schristos     ASSERT(0 == socket_cb_called);
197*fbb2e0a3Schristos 
198*fbb2e0a3Schristos     assert_wait_child(child_pid);
199*fbb2e0a3Schristos   } else {
200*fbb2e0a3Schristos     /* child */
201*fbb2e0a3Schristos     printf("Child is %d\n", getpid());
202*fbb2e0a3Schristos     ASSERT(1 == read(sync_pipe[0], sync_buf, 1)); /* wait for parent */
203*fbb2e0a3Schristos     ASSERT(0 == uv_loop_fork(uv_default_loop()));
204*fbb2e0a3Schristos     ASSERT(0 == socket_cb_called);
205*fbb2e0a3Schristos 
206*fbb2e0a3Schristos     printf("Going to run the loop in the child\n");
207*fbb2e0a3Schristos     socket_cb_read_fd = socket_fds[0];
208*fbb2e0a3Schristos     socket_cb_read_size = 3;
209*fbb2e0a3Schristos     ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
210*fbb2e0a3Schristos     ASSERT(1 == socket_cb_called);
211*fbb2e0a3Schristos     printf("Buf %s\n", socket_cb_read_buf);
212*fbb2e0a3Schristos     ASSERT(0 == strcmp("hi\n", socket_cb_read_buf));
213*fbb2e0a3Schristos   }
214*fbb2e0a3Schristos 
215*fbb2e0a3Schristos   MAKE_VALGRIND_HAPPY();
216*fbb2e0a3Schristos   return 0;
217*fbb2e0a3Schristos }
218*fbb2e0a3Schristos 
219*fbb2e0a3Schristos 
220*fbb2e0a3Schristos static int fork_signal_cb_called;
221*fbb2e0a3Schristos 
fork_signal_to_child_cb(uv_signal_t * handle,int signum)222*fbb2e0a3Schristos void fork_signal_to_child_cb(uv_signal_t* handle, int signum)
223*fbb2e0a3Schristos {
224*fbb2e0a3Schristos   fork_signal_cb_called = signum;
225*fbb2e0a3Schristos   uv_close((uv_handle_t*)handle, NULL);
226*fbb2e0a3Schristos }
227*fbb2e0a3Schristos 
228*fbb2e0a3Schristos 
TEST_IMPL(fork_signal_to_child)229*fbb2e0a3Schristos TEST_IMPL(fork_signal_to_child) {
230*fbb2e0a3Schristos   /* A signal handler installed before forking
231*fbb2e0a3Schristos      is run only in the child when the child is signalled. */
232*fbb2e0a3Schristos   uv_signal_t signal_handle;
233*fbb2e0a3Schristos   pid_t child_pid;
234*fbb2e0a3Schristos   int sync_pipe[2];
235*fbb2e0a3Schristos   char sync_buf[1];
236*fbb2e0a3Schristos 
237*fbb2e0a3Schristos   fork_signal_cb_called = 0;    /* reset */
238*fbb2e0a3Schristos 
239*fbb2e0a3Schristos   ASSERT(0 == pipe(sync_pipe));
240*fbb2e0a3Schristos 
241*fbb2e0a3Schristos   /* Prime the loop. */
242*fbb2e0a3Schristos   run_timer_loop_once();
243*fbb2e0a3Schristos 
244*fbb2e0a3Schristos   ASSERT(0 == uv_signal_init(uv_default_loop(), &signal_handle));
245*fbb2e0a3Schristos   ASSERT(0 == uv_signal_start(&signal_handle, fork_signal_to_child_cb, SIGUSR1));
246*fbb2e0a3Schristos 
247*fbb2e0a3Schristos   child_pid = fork();
248*fbb2e0a3Schristos   ASSERT(child_pid != -1);
249*fbb2e0a3Schristos 
250*fbb2e0a3Schristos   if (child_pid != 0) {
251*fbb2e0a3Schristos     /* parent */
252*fbb2e0a3Schristos     ASSERT(1 == read(sync_pipe[0], sync_buf, 1)); /* wait for child */
253*fbb2e0a3Schristos     ASSERT(0 == kill(child_pid, SIGUSR1));
254*fbb2e0a3Schristos     /* Run the loop, make sure we don't get the signal. */
255*fbb2e0a3Schristos     printf("Running loop in parent\n");
256*fbb2e0a3Schristos     uv_unref((uv_handle_t*)&signal_handle);
257*fbb2e0a3Schristos     ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_NOWAIT));
258*fbb2e0a3Schristos     ASSERT(0 == fork_signal_cb_called);
259*fbb2e0a3Schristos     printf("Waiting for child in parent\n");
260*fbb2e0a3Schristos     assert_wait_child(child_pid);
261*fbb2e0a3Schristos   } else {
262*fbb2e0a3Schristos     /* child */
263*fbb2e0a3Schristos     ASSERT(0 == uv_loop_fork(uv_default_loop()));
264*fbb2e0a3Schristos     ASSERT(1 == write(sync_pipe[1], "1", 1)); /* alert parent */
265*fbb2e0a3Schristos     /* Get the signal. */
266*fbb2e0a3Schristos     ASSERT(0 != uv_loop_alive(uv_default_loop()));
267*fbb2e0a3Schristos     printf("Running loop in child\n");
268*fbb2e0a3Schristos     ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
269*fbb2e0a3Schristos     ASSERT(SIGUSR1 == fork_signal_cb_called);
270*fbb2e0a3Schristos   }
271*fbb2e0a3Schristos 
272*fbb2e0a3Schristos   MAKE_VALGRIND_HAPPY();
273*fbb2e0a3Schristos   return 0;
274*fbb2e0a3Schristos }
275*fbb2e0a3Schristos 
276*fbb2e0a3Schristos 
TEST_IMPL(fork_signal_to_child_closed)277*fbb2e0a3Schristos TEST_IMPL(fork_signal_to_child_closed) {
278*fbb2e0a3Schristos   /* A signal handler installed before forking
279*fbb2e0a3Schristos      doesn't get received anywhere when the child is signalled,
280*fbb2e0a3Schristos      but isnt running the loop. */
281*fbb2e0a3Schristos   uv_signal_t signal_handle;
282*fbb2e0a3Schristos   pid_t child_pid;
283*fbb2e0a3Schristos   int sync_pipe[2];
284*fbb2e0a3Schristos   int sync_pipe2[2];
285*fbb2e0a3Schristos   char sync_buf[1];
286*fbb2e0a3Schristos   int r;
287*fbb2e0a3Schristos 
288*fbb2e0a3Schristos   fork_signal_cb_called = 0;    /* reset */
289*fbb2e0a3Schristos 
290*fbb2e0a3Schristos   ASSERT(0 == pipe(sync_pipe));
291*fbb2e0a3Schristos   ASSERT(0 == pipe(sync_pipe2));
292*fbb2e0a3Schristos 
293*fbb2e0a3Schristos   /* Prime the loop. */
294*fbb2e0a3Schristos   run_timer_loop_once();
295*fbb2e0a3Schristos 
296*fbb2e0a3Schristos   ASSERT(0 == uv_signal_init(uv_default_loop(), &signal_handle));
297*fbb2e0a3Schristos   ASSERT(0 == uv_signal_start(&signal_handle, fork_signal_to_child_cb, SIGUSR1));
298*fbb2e0a3Schristos 
299*fbb2e0a3Schristos   child_pid = fork();
300*fbb2e0a3Schristos   ASSERT(child_pid != -1);
301*fbb2e0a3Schristos 
302*fbb2e0a3Schristos   if (child_pid != 0) {
303*fbb2e0a3Schristos     /* parent */
304*fbb2e0a3Schristos     printf("Wating on child in parent\n");
305*fbb2e0a3Schristos     ASSERT(1 == read(sync_pipe[0], sync_buf, 1)); /* wait for child */
306*fbb2e0a3Schristos     printf("Parent killing child\n");
307*fbb2e0a3Schristos     ASSERT(0 == kill(child_pid, SIGUSR1));
308*fbb2e0a3Schristos     /* Run the loop, make sure we don't get the signal. */
309*fbb2e0a3Schristos     printf("Running loop in parent\n");
310*fbb2e0a3Schristos     uv_unref((uv_handle_t*)&signal_handle); /* so the loop can exit;
311*fbb2e0a3Schristos                                                we *shouldn't* get any signals */
312*fbb2e0a3Schristos     run_timer_loop_once(); /* but while we share a pipe, we do, so
313*fbb2e0a3Schristos                               have something active. */
314*fbb2e0a3Schristos     ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
315*fbb2e0a3Schristos     printf("Signal in parent %d\n", fork_signal_cb_called);
316*fbb2e0a3Schristos     ASSERT(0 == fork_signal_cb_called);
317*fbb2e0a3Schristos     ASSERT(1 == write(sync_pipe2[1], "1", 1)); /* alert child */
318*fbb2e0a3Schristos     printf("Waiting for child in parent\n");
319*fbb2e0a3Schristos     assert_wait_child(child_pid);
320*fbb2e0a3Schristos   } else {
321*fbb2e0a3Schristos     /* Child. Our signal handler should still be installed. */
322*fbb2e0a3Schristos     ASSERT(0 == uv_loop_fork(uv_default_loop()));
323*fbb2e0a3Schristos     printf("Checking loop in child\n");
324*fbb2e0a3Schristos     ASSERT(0 != uv_loop_alive(uv_default_loop()));
325*fbb2e0a3Schristos     printf("Alerting parent in child\n");
326*fbb2e0a3Schristos     ASSERT(1 == write(sync_pipe[1], "1", 1)); /* alert parent */
327*fbb2e0a3Schristos     /* Don't run the loop. Wait for the parent to call us */
328*fbb2e0a3Schristos     printf("Waiting on parent in child\n");
329*fbb2e0a3Schristos     /* Wait for parent. read may fail if the parent tripped an ASSERT
330*fbb2e0a3Schristos        and exited, so this ASSERT is generous.
331*fbb2e0a3Schristos     */
332*fbb2e0a3Schristos     r = read(sync_pipe2[0], sync_buf, 1);
333*fbb2e0a3Schristos     ASSERT(-1 <= r && r <= 1);
334*fbb2e0a3Schristos     ASSERT(0 == fork_signal_cb_called);
335*fbb2e0a3Schristos     printf("Exiting child \n");
336*fbb2e0a3Schristos     /* Note that we're deliberately not running the loop
337*fbb2e0a3Schristos      * in the child, and also not closing the loop's handles,
338*fbb2e0a3Schristos      * so the child default loop can't be cleanly closed.
339*fbb2e0a3Schristos      * We need to explicitly exit to avoid an automatic failure
340*fbb2e0a3Schristos      * in that case.
341*fbb2e0a3Schristos      */
342*fbb2e0a3Schristos     exit(0);
343*fbb2e0a3Schristos   }
344*fbb2e0a3Schristos 
345*fbb2e0a3Schristos   MAKE_VALGRIND_HAPPY();
346*fbb2e0a3Schristos   return 0;
347*fbb2e0a3Schristos }
348*fbb2e0a3Schristos 
349*fbb2e0a3Schristos 
create_file(const char * name)350*fbb2e0a3Schristos static void create_file(const char* name) {
351*fbb2e0a3Schristos   int r;
352*fbb2e0a3Schristos   uv_file file;
353*fbb2e0a3Schristos   uv_fs_t req;
354*fbb2e0a3Schristos 
355*fbb2e0a3Schristos   r = uv_fs_open(NULL, &req, name, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL);
356*fbb2e0a3Schristos   ASSERT(r >= 0);
357*fbb2e0a3Schristos   file = r;
358*fbb2e0a3Schristos   uv_fs_req_cleanup(&req);
359*fbb2e0a3Schristos   r = uv_fs_close(NULL, &req, file, NULL);
360*fbb2e0a3Schristos   ASSERT(r == 0);
361*fbb2e0a3Schristos   uv_fs_req_cleanup(&req);
362*fbb2e0a3Schristos }
363*fbb2e0a3Schristos 
364*fbb2e0a3Schristos 
touch_file(const char * name)365*fbb2e0a3Schristos static void touch_file(const char* name) {
366*fbb2e0a3Schristos   int r;
367*fbb2e0a3Schristos   uv_file file;
368*fbb2e0a3Schristos   uv_fs_t req;
369*fbb2e0a3Schristos   uv_buf_t buf;
370*fbb2e0a3Schristos 
371*fbb2e0a3Schristos   r = uv_fs_open(NULL, &req, name, O_RDWR, 0, NULL);
372*fbb2e0a3Schristos   ASSERT(r >= 0);
373*fbb2e0a3Schristos   file = r;
374*fbb2e0a3Schristos   uv_fs_req_cleanup(&req);
375*fbb2e0a3Schristos 
376*fbb2e0a3Schristos   buf = uv_buf_init("foo", 4);
377*fbb2e0a3Schristos   r = uv_fs_write(NULL, &req, file, &buf, 1, -1, NULL);
378*fbb2e0a3Schristos   ASSERT(r >= 0);
379*fbb2e0a3Schristos   uv_fs_req_cleanup(&req);
380*fbb2e0a3Schristos 
381*fbb2e0a3Schristos   r = uv_fs_close(NULL, &req, file, NULL);
382*fbb2e0a3Schristos   ASSERT(r == 0);
383*fbb2e0a3Schristos   uv_fs_req_cleanup(&req);
384*fbb2e0a3Schristos }
385*fbb2e0a3Schristos 
386*fbb2e0a3Schristos 
387*fbb2e0a3Schristos static int timer_cb_touch_called;
388*fbb2e0a3Schristos 
timer_cb_touch(uv_timer_t * timer)389*fbb2e0a3Schristos static void timer_cb_touch(uv_timer_t* timer) {
390*fbb2e0a3Schristos   uv_close((uv_handle_t*)timer, NULL);
391*fbb2e0a3Schristos   touch_file("watch_file");
392*fbb2e0a3Schristos   timer_cb_touch_called++;
393*fbb2e0a3Schristos }
394*fbb2e0a3Schristos 
395*fbb2e0a3Schristos 
396*fbb2e0a3Schristos static int fs_event_cb_called;
397*fbb2e0a3Schristos 
fs_event_cb_file_current_dir(uv_fs_event_t * handle,const char * filename,int events,int status)398*fbb2e0a3Schristos static void fs_event_cb_file_current_dir(uv_fs_event_t* handle,
399*fbb2e0a3Schristos                                          const char* filename,
400*fbb2e0a3Schristos                                          int events,
401*fbb2e0a3Schristos                                          int status) {
402*fbb2e0a3Schristos   ASSERT(fs_event_cb_called == 0);
403*fbb2e0a3Schristos   ++fs_event_cb_called;
404*fbb2e0a3Schristos   ASSERT(status == 0);
405*fbb2e0a3Schristos #if defined(__APPLE__) || defined(__linux__)
406*fbb2e0a3Schristos   ASSERT(strcmp(filename, "watch_file") == 0);
407*fbb2e0a3Schristos #else
408*fbb2e0a3Schristos   ASSERT(filename == NULL || strcmp(filename, "watch_file") == 0);
409*fbb2e0a3Schristos #endif
410*fbb2e0a3Schristos   uv_close((uv_handle_t*)handle, NULL);
411*fbb2e0a3Schristos }
412*fbb2e0a3Schristos 
413*fbb2e0a3Schristos 
assert_watch_file_current_dir(uv_loop_t * const loop,int file_or_dir)414*fbb2e0a3Schristos static void assert_watch_file_current_dir(uv_loop_t* const loop, int file_or_dir) {
415*fbb2e0a3Schristos   uv_timer_t timer;
416*fbb2e0a3Schristos   uv_fs_event_t fs_event;
417*fbb2e0a3Schristos   int r;
418*fbb2e0a3Schristos 
419*fbb2e0a3Schristos   /* Setup */
420*fbb2e0a3Schristos   remove("watch_file");
421*fbb2e0a3Schristos   create_file("watch_file");
422*fbb2e0a3Schristos 
423*fbb2e0a3Schristos   r = uv_fs_event_init(loop, &fs_event);
424*fbb2e0a3Schristos   ASSERT(r == 0);
425*fbb2e0a3Schristos   /* watching a dir is the only way to get fsevents involved on apple
426*fbb2e0a3Schristos      platforms */
427*fbb2e0a3Schristos   r = uv_fs_event_start(&fs_event,
428*fbb2e0a3Schristos                         fs_event_cb_file_current_dir,
429*fbb2e0a3Schristos                         file_or_dir == 1 ? "." : "watch_file",
430*fbb2e0a3Schristos                         0);
431*fbb2e0a3Schristos   ASSERT(r == 0);
432*fbb2e0a3Schristos 
433*fbb2e0a3Schristos   r = uv_timer_init(loop, &timer);
434*fbb2e0a3Schristos   ASSERT(r == 0);
435*fbb2e0a3Schristos 
436*fbb2e0a3Schristos   r = uv_timer_start(&timer, timer_cb_touch, 100, 0);
437*fbb2e0a3Schristos   ASSERT(r == 0);
438*fbb2e0a3Schristos 
439*fbb2e0a3Schristos   ASSERT(timer_cb_touch_called == 0);
440*fbb2e0a3Schristos   ASSERT(fs_event_cb_called == 0);
441*fbb2e0a3Schristos 
442*fbb2e0a3Schristos   uv_run(loop, UV_RUN_DEFAULT);
443*fbb2e0a3Schristos 
444*fbb2e0a3Schristos   ASSERT(timer_cb_touch_called == 1);
445*fbb2e0a3Schristos   ASSERT(fs_event_cb_called == 1);
446*fbb2e0a3Schristos 
447*fbb2e0a3Schristos   /* Cleanup */
448*fbb2e0a3Schristos   remove("watch_file");
449*fbb2e0a3Schristos   fs_event_cb_called = 0;
450*fbb2e0a3Schristos   timer_cb_touch_called = 0;
451*fbb2e0a3Schristos   uv_run(loop, UV_RUN_DEFAULT); /* flush pending closes */
452*fbb2e0a3Schristos }
453*fbb2e0a3Schristos 
454*fbb2e0a3Schristos 
455*fbb2e0a3Schristos #define FS_TEST_FILE 0
456*fbb2e0a3Schristos #define FS_TEST_DIR 1
457*fbb2e0a3Schristos 
_do_fork_fs_events_child(int file_or_dir)458*fbb2e0a3Schristos static int _do_fork_fs_events_child(int file_or_dir) {
459*fbb2e0a3Schristos   /* basic fsevents work in the child after a fork */
460*fbb2e0a3Schristos   pid_t child_pid;
461*fbb2e0a3Schristos   uv_loop_t loop;
462*fbb2e0a3Schristos 
463*fbb2e0a3Schristos   /* Watch in the parent, prime the loop and/or threads. */
464*fbb2e0a3Schristos   assert_watch_file_current_dir(uv_default_loop(), file_or_dir);
465*fbb2e0a3Schristos   child_pid = fork();
466*fbb2e0a3Schristos   ASSERT(child_pid != -1);
467*fbb2e0a3Schristos 
468*fbb2e0a3Schristos   if (child_pid != 0) {
469*fbb2e0a3Schristos     /* parent */
470*fbb2e0a3Schristos     assert_wait_child(child_pid);
471*fbb2e0a3Schristos   } else {
472*fbb2e0a3Schristos     /* child */
473*fbb2e0a3Schristos     /* Ee can watch in a new loop, but dirs only work
474*fbb2e0a3Schristos        if we're on linux. */
475*fbb2e0a3Schristos #if defined(__APPLE__)
476*fbb2e0a3Schristos     file_or_dir = FS_TEST_FILE;
477*fbb2e0a3Schristos #endif
478*fbb2e0a3Schristos     printf("Running child\n");
479*fbb2e0a3Schristos     uv_loop_init(&loop);
480*fbb2e0a3Schristos     printf("Child first watch\n");
481*fbb2e0a3Schristos     assert_watch_file_current_dir(&loop, file_or_dir);
482*fbb2e0a3Schristos     ASSERT(0 == uv_loop_close(&loop));
483*fbb2e0a3Schristos     printf("Child second watch default loop\n");
484*fbb2e0a3Schristos     /* Ee can watch in the default loop. */
485*fbb2e0a3Schristos     ASSERT(0 == uv_loop_fork(uv_default_loop()));
486*fbb2e0a3Schristos     /* On some platforms (OS X), if we don't update the time now,
487*fbb2e0a3Schristos      * the timer cb fires before the event loop enters uv__io_poll,
488*fbb2e0a3Schristos      * instead of after, meaning we don't see the change! This may be
489*fbb2e0a3Schristos      * a general race.
490*fbb2e0a3Schristos      */
491*fbb2e0a3Schristos     uv_update_time(uv_default_loop());
492*fbb2e0a3Schristos     assert_watch_file_current_dir(uv_default_loop(), file_or_dir);
493*fbb2e0a3Schristos 
494*fbb2e0a3Schristos     /* We can close the parent loop successfully too. This is
495*fbb2e0a3Schristos        especially important on Apple platforms where if we're not
496*fbb2e0a3Schristos        careful trying to touch the CFRunLoop, even just to shut it
497*fbb2e0a3Schristos        down, that we allocated in the FS_TEST_DIR case would crash. */
498*fbb2e0a3Schristos     ASSERT(0 == uv_loop_close(uv_default_loop()));
499*fbb2e0a3Schristos 
500*fbb2e0a3Schristos     printf("Exiting child \n");
501*fbb2e0a3Schristos   }
502*fbb2e0a3Schristos 
503*fbb2e0a3Schristos   MAKE_VALGRIND_HAPPY();
504*fbb2e0a3Schristos   return 0;
505*fbb2e0a3Schristos 
506*fbb2e0a3Schristos }
507*fbb2e0a3Schristos 
508*fbb2e0a3Schristos 
TEST_IMPL(fork_fs_events_child)509*fbb2e0a3Schristos TEST_IMPL(fork_fs_events_child) {
510*fbb2e0a3Schristos #if defined(NO_FS_EVENTS)
511*fbb2e0a3Schristos   RETURN_SKIP(NO_FS_EVENTS);
512*fbb2e0a3Schristos #endif
513*fbb2e0a3Schristos   return _do_fork_fs_events_child(FS_TEST_FILE);
514*fbb2e0a3Schristos }
515*fbb2e0a3Schristos 
516*fbb2e0a3Schristos 
TEST_IMPL(fork_fs_events_child_dir)517*fbb2e0a3Schristos TEST_IMPL(fork_fs_events_child_dir) {
518*fbb2e0a3Schristos #if defined(NO_FS_EVENTS)
519*fbb2e0a3Schristos   RETURN_SKIP(NO_FS_EVENTS);
520*fbb2e0a3Schristos #endif
521*fbb2e0a3Schristos #if defined(__APPLE__) || defined (__linux__)
522*fbb2e0a3Schristos   return _do_fork_fs_events_child(FS_TEST_DIR);
523*fbb2e0a3Schristos #else
524*fbb2e0a3Schristos   /* You can't spin up a cfrunloop thread on an apple platform
525*fbb2e0a3Schristos      and then fork. See
526*fbb2e0a3Schristos      http://objectivistc.tumblr.com/post/16187948939/you-must-exec-a-core-foundation-fork-safety-tale
527*fbb2e0a3Schristos   */
528*fbb2e0a3Schristos   return 0;
529*fbb2e0a3Schristos #endif
530*fbb2e0a3Schristos }
531*fbb2e0a3Schristos 
532*fbb2e0a3Schristos 
TEST_IMPL(fork_fs_events_file_parent_child)533*fbb2e0a3Schristos TEST_IMPL(fork_fs_events_file_parent_child) {
534*fbb2e0a3Schristos #if defined(NO_FS_EVENTS)
535*fbb2e0a3Schristos   RETURN_SKIP(NO_FS_EVENTS);
536*fbb2e0a3Schristos #endif
537*fbb2e0a3Schristos #if defined(__sun) || defined(_AIX) || defined(__MVS__)
538*fbb2e0a3Schristos   /* It's not possible to implement this without additional
539*fbb2e0a3Schristos    * bookkeeping on SunOS. For AIX it is possible, but has to be
540*fbb2e0a3Schristos    * written. See https://github.com/libuv/libuv/pull/846#issuecomment-287170420
541*fbb2e0a3Schristos    * TODO: On z/OS, we need to open another message queue and subscribe to the
542*fbb2e0a3Schristos    * same events as the parent.
543*fbb2e0a3Schristos    */
544*fbb2e0a3Schristos   return 0;
545*fbb2e0a3Schristos #else
546*fbb2e0a3Schristos   /* Establishing a started fs events watcher in the parent should
547*fbb2e0a3Schristos      still work in the child. */
548*fbb2e0a3Schristos   uv_timer_t timer;
549*fbb2e0a3Schristos   uv_fs_event_t fs_event;
550*fbb2e0a3Schristos   int r;
551*fbb2e0a3Schristos   pid_t child_pid;
552*fbb2e0a3Schristos   uv_loop_t* loop;
553*fbb2e0a3Schristos 
554*fbb2e0a3Schristos   loop = uv_default_loop();
555*fbb2e0a3Schristos 
556*fbb2e0a3Schristos   /* Setup */
557*fbb2e0a3Schristos   remove("watch_file");
558*fbb2e0a3Schristos   create_file("watch_file");
559*fbb2e0a3Schristos 
560*fbb2e0a3Schristos   r = uv_fs_event_init(loop, &fs_event);
561*fbb2e0a3Schristos   ASSERT(r == 0);
562*fbb2e0a3Schristos   r = uv_fs_event_start(&fs_event,
563*fbb2e0a3Schristos                         fs_event_cb_file_current_dir,
564*fbb2e0a3Schristos                         "watch_file",
565*fbb2e0a3Schristos                         0);
566*fbb2e0a3Schristos   ASSERT(r == 0);
567*fbb2e0a3Schristos 
568*fbb2e0a3Schristos   r = uv_timer_init(loop, &timer);
569*fbb2e0a3Schristos   ASSERT(r == 0);
570*fbb2e0a3Schristos 
571*fbb2e0a3Schristos   child_pid = fork();
572*fbb2e0a3Schristos   ASSERT(child_pid != -1);
573*fbb2e0a3Schristos   if (child_pid != 0) {
574*fbb2e0a3Schristos     /* parent */
575*fbb2e0a3Schristos     assert_wait_child(child_pid);
576*fbb2e0a3Schristos   } else {
577*fbb2e0a3Schristos     /* child */
578*fbb2e0a3Schristos     printf("Running child\n");
579*fbb2e0a3Schristos     ASSERT(0 == uv_loop_fork(loop));
580*fbb2e0a3Schristos 
581*fbb2e0a3Schristos     r = uv_timer_start(&timer, timer_cb_touch, 100, 0);
582*fbb2e0a3Schristos     ASSERT(r == 0);
583*fbb2e0a3Schristos 
584*fbb2e0a3Schristos     ASSERT(timer_cb_touch_called == 0);
585*fbb2e0a3Schristos     ASSERT(fs_event_cb_called == 0);
586*fbb2e0a3Schristos     printf("Running loop in child \n");
587*fbb2e0a3Schristos     uv_run(loop, UV_RUN_DEFAULT);
588*fbb2e0a3Schristos 
589*fbb2e0a3Schristos     ASSERT(timer_cb_touch_called == 1);
590*fbb2e0a3Schristos     ASSERT(fs_event_cb_called == 1);
591*fbb2e0a3Schristos 
592*fbb2e0a3Schristos     /* Cleanup */
593*fbb2e0a3Schristos     remove("watch_file");
594*fbb2e0a3Schristos     fs_event_cb_called = 0;
595*fbb2e0a3Schristos     timer_cb_touch_called = 0;
596*fbb2e0a3Schristos     uv_run(loop, UV_RUN_DEFAULT); /* Flush pending closes. */
597*fbb2e0a3Schristos   }
598*fbb2e0a3Schristos 
599*fbb2e0a3Schristos 
600*fbb2e0a3Schristos   MAKE_VALGRIND_HAPPY();
601*fbb2e0a3Schristos   return 0;
602*fbb2e0a3Schristos #endif
603*fbb2e0a3Schristos }
604*fbb2e0a3Schristos 
605*fbb2e0a3Schristos 
606*fbb2e0a3Schristos static int work_cb_count;
607*fbb2e0a3Schristos static int after_work_cb_count;
608*fbb2e0a3Schristos 
609*fbb2e0a3Schristos 
work_cb(uv_work_t * req)610*fbb2e0a3Schristos static void work_cb(uv_work_t* req) {
611*fbb2e0a3Schristos   work_cb_count++;
612*fbb2e0a3Schristos }
613*fbb2e0a3Schristos 
614*fbb2e0a3Schristos 
after_work_cb(uv_work_t * req,int status)615*fbb2e0a3Schristos static void after_work_cb(uv_work_t* req, int status) {
616*fbb2e0a3Schristos   ASSERT(status == 0);
617*fbb2e0a3Schristos   after_work_cb_count++;
618*fbb2e0a3Schristos }
619*fbb2e0a3Schristos 
620*fbb2e0a3Schristos 
assert_run_work(uv_loop_t * const loop)621*fbb2e0a3Schristos static void assert_run_work(uv_loop_t* const loop) {
622*fbb2e0a3Schristos   uv_work_t work_req;
623*fbb2e0a3Schristos   int r;
624*fbb2e0a3Schristos 
625*fbb2e0a3Schristos   ASSERT(work_cb_count == 0);
626*fbb2e0a3Schristos   ASSERT(after_work_cb_count == 0);
627*fbb2e0a3Schristos   printf("Queue in %d\n", getpid());
628*fbb2e0a3Schristos   r = uv_queue_work(loop, &work_req, work_cb, after_work_cb);
629*fbb2e0a3Schristos   ASSERT(r == 0);
630*fbb2e0a3Schristos   printf("Running in %d\n", getpid());
631*fbb2e0a3Schristos   uv_run(loop, UV_RUN_DEFAULT);
632*fbb2e0a3Schristos 
633*fbb2e0a3Schristos   ASSERT(work_cb_count == 1);
634*fbb2e0a3Schristos   ASSERT(after_work_cb_count == 1);
635*fbb2e0a3Schristos 
636*fbb2e0a3Schristos   /* cleanup  */
637*fbb2e0a3Schristos   work_cb_count = 0;
638*fbb2e0a3Schristos   after_work_cb_count = 0;
639*fbb2e0a3Schristos }
640*fbb2e0a3Schristos 
641*fbb2e0a3Schristos 
642*fbb2e0a3Schristos #ifndef __MVS__
TEST_IMPL(fork_threadpool_queue_work_simple)643*fbb2e0a3Schristos TEST_IMPL(fork_threadpool_queue_work_simple) {
644*fbb2e0a3Schristos   /* The threadpool works in a child process. */
645*fbb2e0a3Schristos 
646*fbb2e0a3Schristos   pid_t child_pid;
647*fbb2e0a3Schristos   uv_loop_t loop;
648*fbb2e0a3Schristos 
649*fbb2e0a3Schristos   /* Prime the pool and default loop. */
650*fbb2e0a3Schristos   assert_run_work(uv_default_loop());
651*fbb2e0a3Schristos 
652*fbb2e0a3Schristos   child_pid = fork();
653*fbb2e0a3Schristos   ASSERT(child_pid != -1);
654*fbb2e0a3Schristos 
655*fbb2e0a3Schristos   if (child_pid != 0) {
656*fbb2e0a3Schristos     /* Parent. We can still run work. */
657*fbb2e0a3Schristos     assert_run_work(uv_default_loop());
658*fbb2e0a3Schristos     assert_wait_child(child_pid);
659*fbb2e0a3Schristos   } else {
660*fbb2e0a3Schristos     /* Child. We can work in a new loop. */
661*fbb2e0a3Schristos     printf("Running child in %d\n", getpid());
662*fbb2e0a3Schristos     uv_loop_init(&loop);
663*fbb2e0a3Schristos     printf("Child first watch\n");
664*fbb2e0a3Schristos     assert_run_work(&loop);
665*fbb2e0a3Schristos     uv_loop_close(&loop);
666*fbb2e0a3Schristos     printf("Child second watch default loop\n");
667*fbb2e0a3Schristos     /* We can work in the default loop. */
668*fbb2e0a3Schristos     ASSERT(0 == uv_loop_fork(uv_default_loop()));
669*fbb2e0a3Schristos     assert_run_work(uv_default_loop());
670*fbb2e0a3Schristos     printf("Exiting child \n");
671*fbb2e0a3Schristos   }
672*fbb2e0a3Schristos 
673*fbb2e0a3Schristos 
674*fbb2e0a3Schristos   MAKE_VALGRIND_HAPPY();
675*fbb2e0a3Schristos   return 0;
676*fbb2e0a3Schristos }
677*fbb2e0a3Schristos #endif /* !__MVS__ */
678*fbb2e0a3Schristos 
679*fbb2e0a3Schristos #else
680*fbb2e0a3Schristos 
681*fbb2e0a3Schristos typedef int file_has_no_tests; /* ISO C forbids an empty translation unit. */
682*fbb2e0a3Schristos 
683*fbb2e0a3Schristos #endif /* !_WIN32 */
684