test-fork.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  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. /* These tests are Unix only. */
  22. #ifndef _WIN32
  23. #include <unistd.h>
  24. #include <sys/wait.h>
  25. #include <sys/socket.h>
  26. #include <string.h>
  27. #include "uv.h"
  28. #include "task.h"
  29. static int timer_cb_called;
  30. static int socket_cb_called;
  31. static void timer_cb(uv_timer_t* timer) {
  32. timer_cb_called++;
  33. uv_close((uv_handle_t*) timer, NULL);
  34. }
  35. static int socket_cb_read_fd;
  36. static int socket_cb_read_size;
  37. static char socket_cb_read_buf[1024];
  38. static void socket_cb(uv_poll_t* poll, int status, int events) {
  39. ssize_t cnt;
  40. socket_cb_called++;
  41. ASSERT(0 == status);
  42. printf("Socket cb got events %d\n", events);
  43. ASSERT(UV_READABLE == (events & UV_READABLE));
  44. if (socket_cb_read_fd) {
  45. cnt = read(socket_cb_read_fd, socket_cb_read_buf, socket_cb_read_size);
  46. ASSERT(cnt == socket_cb_read_size);
  47. }
  48. uv_close((uv_handle_t*) poll, NULL);
  49. }
  50. static void run_timer_loop_once(void) {
  51. uv_loop_t* loop;
  52. uv_timer_t timer_handle;
  53. loop = uv_default_loop();
  54. timer_cb_called = 0; /* Reset for the child. */
  55. ASSERT(0 == uv_timer_init(loop, &timer_handle));
  56. ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 1, 0));
  57. ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
  58. ASSERT(1 == timer_cb_called);
  59. }
  60. static void assert_wait_child(pid_t child_pid) {
  61. pid_t waited_pid;
  62. int child_stat;
  63. waited_pid = waitpid(child_pid, &child_stat, 0);
  64. printf("Waited pid is %d with status %d\n", waited_pid, child_stat);
  65. if (waited_pid == -1) {
  66. perror("Failed to wait");
  67. }
  68. ASSERT(child_pid == waited_pid);
  69. ASSERT(WIFEXITED(child_stat)); /* Clean exit, not a signal. */
  70. ASSERT(!WIFSIGNALED(child_stat));
  71. ASSERT(0 == WEXITSTATUS(child_stat));
  72. }
  73. TEST_IMPL(fork_timer) {
  74. /* Timers continue to work after we fork. */
  75. /*
  76. * Establish the loop before we fork to make sure that it
  77. * has state to get reset after the fork.
  78. */
  79. pid_t child_pid;
  80. run_timer_loop_once();
  81. child_pid = fork();
  82. ASSERT(child_pid != -1);
  83. if (child_pid != 0) {
  84. /* parent */
  85. assert_wait_child(child_pid);
  86. } else {
  87. /* child */
  88. ASSERT(0 == uv_loop_fork(uv_default_loop()));
  89. run_timer_loop_once();
  90. }
  91. MAKE_VALGRIND_HAPPY();
  92. return 0;
  93. }
  94. TEST_IMPL(fork_socketpair) {
  95. /* A socket opened in the parent and accept'd in the
  96. child works after a fork. */
  97. pid_t child_pid;
  98. int socket_fds[2];
  99. uv_poll_t poll_handle;
  100. /* Prime the loop. */
  101. run_timer_loop_once();
  102. ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds));
  103. /* Create the server watcher in the parent, use it in the child. */
  104. ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, socket_fds[0]));
  105. child_pid = fork();
  106. ASSERT(child_pid != -1);
  107. if (child_pid != 0) {
  108. /* parent */
  109. ASSERT(3 == send(socket_fds[1], "hi\n", 3, 0));
  110. assert_wait_child(child_pid);
  111. } else {
  112. /* child */
  113. ASSERT(0 == uv_loop_fork(uv_default_loop()));
  114. ASSERT(0 == socket_cb_called);
  115. ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, socket_cb));
  116. printf("Going to run the loop in the child\n");
  117. ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
  118. ASSERT(1 == socket_cb_called);
  119. }
  120. MAKE_VALGRIND_HAPPY();
  121. return 0;
  122. }
  123. TEST_IMPL(fork_socketpair_started) {
  124. /* A socket opened in the parent and accept'd in the
  125. child works after a fork, even if the watcher was already
  126. started, and then stopped in the parent. */
  127. pid_t child_pid;
  128. int socket_fds[2];
  129. int sync_pipe[2];
  130. char sync_buf[1];
  131. uv_poll_t poll_handle;
  132. ASSERT(0 == pipe(sync_pipe));
  133. /* Prime the loop. */
  134. run_timer_loop_once();
  135. ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds));
  136. /* Create and start the server watcher in the parent, use it in the child. */
  137. ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, socket_fds[0]));
  138. ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, socket_cb));
  139. /* Run the loop AFTER the poll watcher is registered to make sure it
  140. gets passed to the kernel. Use NOWAIT and expect a non-zero
  141. return to prove the poll watcher is active.
  142. */
  143. ASSERT(1 == uv_run(uv_default_loop(), UV_RUN_NOWAIT));
  144. child_pid = fork();
  145. ASSERT(child_pid != -1);
  146. if (child_pid != 0) {
  147. /* parent */
  148. ASSERT(0 == uv_poll_stop(&poll_handle));
  149. uv_close((uv_handle_t*)&poll_handle, NULL);
  150. ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
  151. ASSERT(0 == socket_cb_called);
  152. ASSERT(1 == write(sync_pipe[1], "1", 1)); /* alert child */
  153. ASSERT(3 == send(socket_fds[1], "hi\n", 3, 0));
  154. ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
  155. ASSERT(0 == socket_cb_called);
  156. assert_wait_child(child_pid);
  157. } else {
  158. /* child */
  159. printf("Child is %d\n", getpid());
  160. ASSERT(1 == read(sync_pipe[0], sync_buf, 1)); /* wait for parent */
  161. ASSERT(0 == uv_loop_fork(uv_default_loop()));
  162. ASSERT(0 == socket_cb_called);
  163. printf("Going to run the loop in the child\n");
  164. socket_cb_read_fd = socket_fds[0];
  165. socket_cb_read_size = 3;
  166. ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
  167. ASSERT(1 == socket_cb_called);
  168. printf("Buf %s\n", socket_cb_read_buf);
  169. ASSERT(0 == strcmp("hi\n", socket_cb_read_buf));
  170. }
  171. MAKE_VALGRIND_HAPPY();
  172. return 0;
  173. }
  174. static int fork_signal_cb_called;
  175. void fork_signal_to_child_cb(uv_signal_t* handle, int signum)
  176. {
  177. fork_signal_cb_called = signum;
  178. uv_close((uv_handle_t*)handle, NULL);
  179. }
  180. TEST_IMPL(fork_signal_to_child) {
  181. /* A signal handler installed before forking
  182. is run only in the child when the child is signalled. */
  183. uv_signal_t signal_handle;
  184. pid_t child_pid;
  185. int sync_pipe[2];
  186. char sync_buf[1];
  187. fork_signal_cb_called = 0; /* reset */
  188. ASSERT(0 == pipe(sync_pipe));
  189. /* Prime the loop. */
  190. run_timer_loop_once();
  191. ASSERT(0 == uv_signal_init(uv_default_loop(), &signal_handle));
  192. ASSERT(0 == uv_signal_start(&signal_handle, fork_signal_to_child_cb, SIGUSR1));
  193. child_pid = fork();
  194. ASSERT(child_pid != -1);
  195. if (child_pid != 0) {
  196. /* parent */
  197. ASSERT(1 == read(sync_pipe[0], sync_buf, 1)); /* wait for child */
  198. ASSERT(0 == kill(child_pid, SIGUSR1));
  199. /* Run the loop, make sure we don't get the signal. */
  200. printf("Running loop in parent\n");
  201. uv_unref((uv_handle_t*)&signal_handle);
  202. ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_NOWAIT));
  203. ASSERT(0 == fork_signal_cb_called);
  204. printf("Waiting for child in parent\n");
  205. assert_wait_child(child_pid);
  206. } else {
  207. /* child */
  208. ASSERT(0 == uv_loop_fork(uv_default_loop()));
  209. ASSERT(1 == write(sync_pipe[1], "1", 1)); /* alert parent */
  210. /* Get the signal. */
  211. ASSERT(0 != uv_loop_alive(uv_default_loop()));
  212. printf("Running loop in child\n");
  213. ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
  214. ASSERT(SIGUSR1 == fork_signal_cb_called);
  215. }
  216. MAKE_VALGRIND_HAPPY();
  217. return 0;
  218. }
  219. TEST_IMPL(fork_signal_to_child_closed) {
  220. /* A signal handler installed before forking
  221. doesn't get received anywhere when the child is signalled,
  222. but isnt running the loop. */
  223. uv_signal_t signal_handle;
  224. pid_t child_pid;
  225. int sync_pipe[2];
  226. int sync_pipe2[2];
  227. char sync_buf[1];
  228. int r;
  229. fork_signal_cb_called = 0; /* reset */
  230. ASSERT(0 == pipe(sync_pipe));
  231. ASSERT(0 == pipe(sync_pipe2));
  232. /* Prime the loop. */
  233. run_timer_loop_once();
  234. ASSERT(0 == uv_signal_init(uv_default_loop(), &signal_handle));
  235. ASSERT(0 == uv_signal_start(&signal_handle, fork_signal_to_child_cb, SIGUSR1));
  236. child_pid = fork();
  237. ASSERT(child_pid != -1);
  238. if (child_pid != 0) {
  239. /* parent */
  240. printf("Wating on child in parent\n");
  241. ASSERT(1 == read(sync_pipe[0], sync_buf, 1)); /* wait for child */
  242. printf("Parent killing child\n");
  243. ASSERT(0 == kill(child_pid, SIGUSR1));
  244. /* Run the loop, make sure we don't get the signal. */
  245. printf("Running loop in parent\n");
  246. uv_unref((uv_handle_t*)&signal_handle); /* so the loop can exit;
  247. we *shouldn't* get any signals */
  248. run_timer_loop_once(); /* but while we share a pipe, we do, so
  249. have something active. */
  250. ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
  251. printf("Signal in parent %d\n", fork_signal_cb_called);
  252. ASSERT(0 == fork_signal_cb_called);
  253. ASSERT(1 == write(sync_pipe2[1], "1", 1)); /* alert child */
  254. printf("Waiting for child in parent\n");
  255. assert_wait_child(child_pid);
  256. } else {
  257. /* Child. Our signal handler should still be installed. */
  258. ASSERT(0 == uv_loop_fork(uv_default_loop()));
  259. printf("Checking loop in child\n");
  260. ASSERT(0 != uv_loop_alive(uv_default_loop()));
  261. printf("Alerting parent in child\n");
  262. ASSERT(1 == write(sync_pipe[1], "1", 1)); /* alert parent */
  263. /* Don't run the loop. Wait for the parent to call us */
  264. printf("Waiting on parent in child\n");
  265. /* Wait for parent. read may fail if the parent tripped an ASSERT
  266. and exited, so this ASSERT is generous.
  267. */
  268. r = read(sync_pipe2[0], sync_buf, 1);
  269. ASSERT(-1 <= r && r <= 1);
  270. ASSERT(0 == fork_signal_cb_called);
  271. printf("Exiting child \n");
  272. /* Note that we're deliberately not running the loop
  273. * in the child, and also not closing the loop's handles,
  274. * so the child default loop can't be cleanly closed.
  275. * We need to explicitly exit to avoid an automatic failure
  276. * in that case.
  277. */
  278. exit(0);
  279. }
  280. MAKE_VALGRIND_HAPPY();
  281. return 0;
  282. }
  283. static void create_file(const char* name) {
  284. int r;
  285. uv_file file;
  286. uv_fs_t req;
  287. r = uv_fs_open(NULL, &req, name, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL);
  288. ASSERT(r >= 0);
  289. file = r;
  290. uv_fs_req_cleanup(&req);
  291. r = uv_fs_close(NULL, &req, file, NULL);
  292. ASSERT(r == 0);
  293. uv_fs_req_cleanup(&req);
  294. }
  295. static void touch_file(const char* name) {
  296. int r;
  297. uv_file file;
  298. uv_fs_t req;
  299. uv_buf_t buf;
  300. r = uv_fs_open(NULL, &req, name, O_RDWR, 0, NULL);
  301. ASSERT(r >= 0);
  302. file = r;
  303. uv_fs_req_cleanup(&req);
  304. buf = uv_buf_init("foo", 4);
  305. r = uv_fs_write(NULL, &req, file, &buf, 1, -1, NULL);
  306. ASSERT(r >= 0);
  307. uv_fs_req_cleanup(&req);
  308. r = uv_fs_close(NULL, &req, file, NULL);
  309. ASSERT(r == 0);
  310. uv_fs_req_cleanup(&req);
  311. }
  312. static int timer_cb_touch_called;
  313. static void timer_cb_touch(uv_timer_t* timer) {
  314. uv_close((uv_handle_t*)timer, NULL);
  315. touch_file("watch_file");
  316. timer_cb_touch_called++;
  317. }
  318. static int fs_event_cb_called;
  319. static void fs_event_cb_file_current_dir(uv_fs_event_t* handle,
  320. const char* filename,
  321. int events,
  322. int status) {
  323. ASSERT(fs_event_cb_called == 0);
  324. ++fs_event_cb_called;
  325. ASSERT(status == 0);
  326. #if defined(__APPLE__) || defined(__linux__)
  327. ASSERT(strcmp(filename, "watch_file") == 0);
  328. #else
  329. ASSERT(filename == NULL || strcmp(filename, "watch_file") == 0);
  330. #endif
  331. uv_close((uv_handle_t*)handle, NULL);
  332. }
  333. static void assert_watch_file_current_dir(uv_loop_t* const loop, int file_or_dir) {
  334. uv_timer_t timer;
  335. uv_fs_event_t fs_event;
  336. int r;
  337. /* Setup */
  338. remove("watch_file");
  339. create_file("watch_file");
  340. r = uv_fs_event_init(loop, &fs_event);
  341. ASSERT(r == 0);
  342. /* watching a dir is the only way to get fsevents involved on apple
  343. platforms */
  344. r = uv_fs_event_start(&fs_event,
  345. fs_event_cb_file_current_dir,
  346. file_or_dir == 1 ? "." : "watch_file",
  347. 0);
  348. ASSERT(r == 0);
  349. r = uv_timer_init(loop, &timer);
  350. ASSERT(r == 0);
  351. r = uv_timer_start(&timer, timer_cb_touch, 100, 0);
  352. ASSERT(r == 0);
  353. ASSERT(timer_cb_touch_called == 0);
  354. ASSERT(fs_event_cb_called == 0);
  355. uv_run(loop, UV_RUN_DEFAULT);
  356. ASSERT(timer_cb_touch_called == 1);
  357. ASSERT(fs_event_cb_called == 1);
  358. /* Cleanup */
  359. remove("watch_file");
  360. fs_event_cb_called = 0;
  361. timer_cb_touch_called = 0;
  362. uv_run(loop, UV_RUN_DEFAULT); /* flush pending closes */
  363. }
  364. #define FS_TEST_FILE 0
  365. #define FS_TEST_DIR 1
  366. static int _do_fork_fs_events_child(int file_or_dir) {
  367. /* basic fsevents work in the child after a fork */
  368. pid_t child_pid;
  369. uv_loop_t loop;
  370. /* Watch in the parent, prime the loop and/or threads. */
  371. assert_watch_file_current_dir(uv_default_loop(), file_or_dir);
  372. child_pid = fork();
  373. ASSERT(child_pid != -1);
  374. if (child_pid != 0) {
  375. /* parent */
  376. assert_wait_child(child_pid);
  377. } else {
  378. /* child */
  379. /* Ee can watch in a new loop, but dirs only work
  380. if we're on linux. */
  381. #if defined(__APPLE__)
  382. file_or_dir = FS_TEST_FILE;
  383. #endif
  384. printf("Running child\n");
  385. uv_loop_init(&loop);
  386. printf("Child first watch\n");
  387. assert_watch_file_current_dir(&loop, file_or_dir);
  388. ASSERT(0 == uv_loop_close(&loop));
  389. printf("Child second watch default loop\n");
  390. /* Ee can watch in the default loop. */
  391. ASSERT(0 == uv_loop_fork(uv_default_loop()));
  392. /* On some platforms (OS X), if we don't update the time now,
  393. * the timer cb fires before the event loop enters uv__io_poll,
  394. * instead of after, meaning we don't see the change! This may be
  395. * a general race.
  396. */
  397. uv_update_time(uv_default_loop());
  398. assert_watch_file_current_dir(uv_default_loop(), file_or_dir);
  399. /* We can close the parent loop successfully too. This is
  400. especially important on Apple platforms where if we're not
  401. careful trying to touch the CFRunLoop, even just to shut it
  402. down, that we allocated in the FS_TEST_DIR case would crash. */
  403. ASSERT(0 == uv_loop_close(uv_default_loop()));
  404. printf("Exiting child \n");
  405. }
  406. MAKE_VALGRIND_HAPPY();
  407. return 0;
  408. }
  409. TEST_IMPL(fork_fs_events_child) {
  410. #if defined(NO_FS_EVENTS)
  411. RETURN_SKIP(NO_FS_EVENTS);
  412. #endif
  413. return _do_fork_fs_events_child(FS_TEST_FILE);
  414. }
  415. TEST_IMPL(fork_fs_events_child_dir) {
  416. #if defined(NO_FS_EVENTS)
  417. RETURN_SKIP(NO_FS_EVENTS);
  418. #endif
  419. #if defined(__APPLE__) || defined (__linux__)
  420. return _do_fork_fs_events_child(FS_TEST_DIR);
  421. #else
  422. /* You can't spin up a cfrunloop thread on an apple platform
  423. and then fork. See
  424. http://objectivistc.tumblr.com/post/16187948939/you-must-exec-a-core-foundation-fork-safety-tale
  425. */
  426. return 0;
  427. #endif
  428. }
  429. TEST_IMPL(fork_fs_events_file_parent_child) {
  430. #if defined(NO_FS_EVENTS)
  431. RETURN_SKIP(NO_FS_EVENTS);
  432. #endif
  433. #if defined(__sun) || defined(_AIX) || defined(__MVS__)
  434. /* It's not possible to implement this without additional
  435. * bookkeeping on SunOS. For AIX it is possible, but has to be
  436. * written. See https://github.com/libuv/libuv/pull/846#issuecomment-287170420
  437. * TODO: On z/OS, we need to open another message queue and subscribe to the
  438. * same events as the parent.
  439. */
  440. return 0;
  441. #else
  442. /* Establishing a started fs events watcher in the parent should
  443. still work in the child. */
  444. uv_timer_t timer;
  445. uv_fs_event_t fs_event;
  446. int r;
  447. pid_t child_pid;
  448. uv_loop_t* loop;
  449. loop = uv_default_loop();
  450. /* Setup */
  451. remove("watch_file");
  452. create_file("watch_file");
  453. r = uv_fs_event_init(loop, &fs_event);
  454. ASSERT(r == 0);
  455. r = uv_fs_event_start(&fs_event,
  456. fs_event_cb_file_current_dir,
  457. "watch_file",
  458. 0);
  459. ASSERT(r == 0);
  460. r = uv_timer_init(loop, &timer);
  461. ASSERT(r == 0);
  462. child_pid = fork();
  463. ASSERT(child_pid != -1);
  464. if (child_pid != 0) {
  465. /* parent */
  466. assert_wait_child(child_pid);
  467. } else {
  468. /* child */
  469. printf("Running child\n");
  470. ASSERT(0 == uv_loop_fork(loop));
  471. r = uv_timer_start(&timer, timer_cb_touch, 100, 0);
  472. ASSERT(r == 0);
  473. ASSERT(timer_cb_touch_called == 0);
  474. ASSERT(fs_event_cb_called == 0);
  475. printf("Running loop in child \n");
  476. uv_run(loop, UV_RUN_DEFAULT);
  477. ASSERT(timer_cb_touch_called == 1);
  478. ASSERT(fs_event_cb_called == 1);
  479. /* Cleanup */
  480. remove("watch_file");
  481. fs_event_cb_called = 0;
  482. timer_cb_touch_called = 0;
  483. uv_run(loop, UV_RUN_DEFAULT); /* Flush pending closes. */
  484. }
  485. MAKE_VALGRIND_HAPPY();
  486. return 0;
  487. #endif
  488. }
  489. static int work_cb_count;
  490. static int after_work_cb_count;
  491. static void work_cb(uv_work_t* req) {
  492. work_cb_count++;
  493. }
  494. static void after_work_cb(uv_work_t* req, int status) {
  495. ASSERT(status == 0);
  496. after_work_cb_count++;
  497. }
  498. static void assert_run_work(uv_loop_t* const loop) {
  499. uv_work_t work_req;
  500. int r;
  501. ASSERT(work_cb_count == 0);
  502. ASSERT(after_work_cb_count == 0);
  503. printf("Queue in %d\n", getpid());
  504. r = uv_queue_work(loop, &work_req, work_cb, after_work_cb);
  505. ASSERT(r == 0);
  506. printf("Running in %d\n", getpid());
  507. uv_run(loop, UV_RUN_DEFAULT);
  508. ASSERT(work_cb_count == 1);
  509. ASSERT(after_work_cb_count == 1);
  510. /* cleanup */
  511. work_cb_count = 0;
  512. after_work_cb_count = 0;
  513. }
  514. #ifndef __MVS__
  515. TEST_IMPL(fork_threadpool_queue_work_simple) {
  516. /* The threadpool works in a child process. */
  517. pid_t child_pid;
  518. uv_loop_t loop;
  519. /* Prime the pool and default loop. */
  520. assert_run_work(uv_default_loop());
  521. child_pid = fork();
  522. ASSERT(child_pid != -1);
  523. if (child_pid != 0) {
  524. /* Parent. We can still run work. */
  525. assert_run_work(uv_default_loop());
  526. assert_wait_child(child_pid);
  527. } else {
  528. /* Child. We can work in a new loop. */
  529. printf("Running child in %d\n", getpid());
  530. uv_loop_init(&loop);
  531. printf("Child first watch\n");
  532. assert_run_work(&loop);
  533. uv_loop_close(&loop);
  534. printf("Child second watch default loop\n");
  535. /* We can work in the default loop. */
  536. ASSERT(0 == uv_loop_fork(uv_default_loop()));
  537. assert_run_work(uv_default_loop());
  538. printf("Exiting child \n");
  539. }
  540. MAKE_VALGRIND_HAPPY();
  541. return 0;
  542. }
  543. #endif /* !__MVS__ */
  544. #else
  545. typedef int file_has_no_tests; /* ISO C forbids an empty translation unit. */
  546. #endif /* !_WIN32 */