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