ATF_TC_BODY (child_pid, tc) { atf_process_stream_t outsb, errsb; atf_process_child_t child; atf_process_status_t status; pid_t pid; RE (atf_process_stream_init_capture (&outsb)); RE (atf_process_stream_init_inherit (&errsb)); RE (atf_process_fork (&child, child_report_pid, &outsb, &errsb, NULL)); ATF_CHECK_EQ (read (atf_process_child_stdout (&child), &pid, sizeof (pid)), sizeof (pid)); printf ("Expected PID: %d\n", (int) atf_process_child_pid (&child)); printf ("Actual PID: %d\n", (int) pid); ATF_CHECK_EQ (atf_process_child_pid (&child), pid); RE (atf_process_child_wait (&child, &status)); atf_process_status_fini (&status); atf_process_stream_fini (&outsb); atf_process_stream_fini (&errsb); }
impl::child::~child(void) { if (!m_waited) { ::kill(atf_process_child_pid(&m_child), SIGTERM); atf_process_status_t s; atf_error_t err = atf_process_child_wait(&m_child, &s); INV(!atf_is_error(err)); atf_process_status_fini(&s); } }
impl::child::~child(void) { if (!m_waited) { ::kill(atf_process_child_pid(&m_child), SIGTERM); atf_process_status_t s; #if defined(__minix) && !defined(NDEBUG) atf_error_t err = #endif /* defined(__minix) && !defined(NDEBUG) */ atf_process_child_wait(&m_child, &s); INV(!atf_is_error(err)); atf_process_status_fini(&s); } }
ATF_TC_BODY (child_wait_eintr, tc) { atf_process_child_t child; atf_process_status_t status; { atf_process_stream_t outsb, errsb; RE (atf_process_stream_init_capture (&outsb)); RE (atf_process_stream_init_inherit (&errsb)); RE (atf_process_fork (&child, child_spawn_loop_and_wait_eintr, &outsb, &errsb, NULL)); atf_process_stream_fini (&outsb); atf_process_stream_fini (&errsb); } { /* Wait until the child process performs the wait call. This is * racy, because the message we get from it is sent *before* * doing the real system call... but I can't figure any other way * to do this. */ char buf[16]; printf ("Waiting for child to issue wait(2)\n"); ATF_REQUIRE (read (atf_process_child_stdout (&child), buf, sizeof (buf)) > 0); sleep (1); } printf ("Interrupting child's wait(2) call\n"); kill (atf_process_child_pid (&child), SIGHUP); printf ("Waiting for child's completion\n"); RE (atf_process_child_wait (&child, &status)); ATF_REQUIRE (atf_process_status_exited (&status)); ATF_REQUIRE_EQ (atf_process_status_exitstatus (&status), EXIT_SUCCESS); atf_process_status_fini (&status); }
static void child_spawn_loop_and_wait_eintr (void *v) { atf_process_child_t child; atf_process_status_t status; struct sigaction sighup, old_sighup; #define RE_ABORT(expr) \ do { \ atf_error_t _aux_err = expr; \ if (atf_is_error(_aux_err)) { \ atf_error_free(_aux_err); \ abort(); \ } \ } while (0) { atf_process_stream_t outsb, errsb; RE_ABORT (atf_process_stream_init_capture (&outsb)); RE_ABORT (atf_process_stream_init_inherit (&errsb)); RE_ABORT (atf_process_fork (&child, child_loop, &outsb, &errsb, NULL)); atf_process_stream_fini (&outsb); atf_process_stream_fini (&errsb); } sighup.sa_handler = nop_signal; sigemptyset (&sighup.sa_mask); sighup.sa_flags = 0; if (sigaction (SIGHUP, &sighup, &old_sighup) == -1) abort (); printf ("waiting\n"); fflush (stdout); fprintf (stderr, "Child entering wait(2)\n"); atf_error_t err = atf_process_child_wait (&child, &status); fprintf (stderr, "Child's wait(2) terminated\n"); if (!atf_is_error (err)) { fprintf (stderr, "wait completed successfully (not interrupted)\n"); abort (); } if (!atf_error_is (err, "libc")) { fprintf (stderr, "wait did not raise libc_error\n"); abort (); } if (atf_libc_error_code (err) != EINTR) { fprintf (stderr, "libc_error is not EINTR\n"); abort (); } atf_error_free (err); sigaction (SIGHUP, &old_sighup, NULL); fprintf (stderr, "Child is killing subchild\n"); kill (atf_process_child_pid (&child), SIGTERM); RE_ABORT (atf_process_child_wait (&child, &status)); atf_process_status_fini (&status); #undef RE_ABORT exit (EXIT_SUCCESS); }
pid_t impl::child::pid(void) const { return atf_process_child_pid(&m_child); }