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