Exemplo n.º 1
0
/// Waits for completion of any forked process.
///
/// \return A pointer to an object describing the waited-for subprocess.
executor::exit_handle
executor::executor_handle::wait_any(void)
{
    signals::check_interrupt();
    const process::status status = process::wait_any();
    return _pimpl->post_wait(status.dead_pid(), status);
}
Exemplo n.º 2
0
/// Blocks to wait for completion of any subprocess.
///
/// \return The termination status of the child process that terminated.
///
/// \throw process::system_error If the call to wait(2) fails.
process::status
process::wait_any(void)
{
    const process::status status = safe_wait();
    {
        signals::interrupts_inhibiter inhibiter;
        signals::remove_pid_to_kill(status.dead_pid());
    }
    return status;
}
Exemplo n.º 3
0
/// Tests an exec function with no arguments.
///
/// \param tc The calling test case.
/// \param do_exec The exec function to test.
static void
check_exec_no_args(const atf::tests::tc* tc, const exec_function do_exec)
{
    std::auto_ptr< process::child > child = process::child::fork_files(
        child_exec(do_exec, get_helpers(tc), process::args_vector()),
        fs::path("stdout"), fs::path("stderr"));
    const process::status status = child->wait();
    ATF_REQUIRE(status.exited());
    ATF_REQUIRE_EQ(EXIT_FAILURE, status.exitstatus());
    ATF_REQUIRE(atf::utils::grep_file("Must provide a helper name", "stderr"));
}
Exemplo n.º 4
0
/// Generates a core dump, if possible.
///
/// \post If this fails to generate a core file, the test case is marked as
/// skipped.  The caller can rely on this when attempting further checks on the
/// core dump by assuming that the core dump exists somewhere.
///
/// \param test_case Pointer to the caller test case, needed to obtain the path
///     to the source directory.
/// \param base_name Name of the binary to execute, which will be a copy of a
///     helper binary that always crashes.  This name should later be part of
///     the core filename.
///
/// \return The status of the crashed binary.
static process::status
generate_core(const atf::tests::tc* test_case, const char* base_name)
{
    utils::unlimit_core_size();

    const fs::path helper = fs::path(test_case->get_config_var("srcdir")) /
        "stacktrace_helper";

    const process::status status = process::child::fork_files(
        crash_me(helper, base_name),
        fs::path("unused.out"), fs::path("unused.err"))->wait();
    ATF_REQUIRE(status.signaled());
    if (!status.coredump())
        ATF_SKIP("Test failed to generate core dump");
    return status;
}
Exemplo n.º 5
0
/// Tests an exec function with some arguments.
///
/// \param tc The calling test case.
/// \param do_exec The exec function to test.
static void
check_exec_some_args(const atf::tests::tc* tc, const exec_function do_exec)
{
    process::args_vector args;
    args.push_back("print-args");
    args.push_back("foo");
    args.push_back("bar");

    std::auto_ptr< process::child > child = process::child::fork_files(
        child_exec(do_exec, get_helpers(tc), args),
        fs::path("stdout"), fs::path("stderr"));
    const process::status status = child->wait();
    ATF_REQUIRE(status.exited());
    ATF_REQUIRE_EQ(EXIT_SUCCESS, status.exitstatus());
    ATF_REQUIRE(atf::utils::grep_file("argv\\[1\\] = print-args", "stdout"));
    ATF_REQUIRE(atf::utils::grep_file("argv\\[2\\] = foo", "stdout"));
    ATF_REQUIRE(atf::utils::grep_file("argv\\[3\\] = bar", "stdout"));
}
Exemplo n.º 6
0
    /// Common code to run after any of the wait calls.
    ///
    /// \param handle The exec_handle of the terminated subprocess.
    /// \param status The exit status of the terminated subprocess.
    ///
    /// \return A pointer to an object describing the waited-for subprocess.
    executor::exit_handle
    post_wait(const executor::exec_handle handle, const process::status& status)
    {
        PRE(handle == status.dead_pid());
        LI(F("Waited for subprocess with exec_handle %s") % handle);

        process::terminate_group(status.dead_pid());

        const exec_data_map::iterator iter = all_exec_data.find(handle);
        exec_data_ptr& data = (*iter).second;
        data->timer.unprogram();

        // It is tempting to assert here (and old code did) that, if the timer
        // has fired, the process has been forcibly killed by us.  This is not
        // always the case though: for short-lived processes and with very short
        // timeouts (think 1ms), it is possible for scheduling decisions to
        // allow the subprocess to finish while at the same time cause the timer
        // to fire.  So we do not assert this any longer and just rely on the
        // timer expiration to check if the process timed out or not.  If the
        // process did finish but the timer expired... oh well, we do not detect
        // this correctly but we don't care because this should not really
        // happen.

        if (!fs::exists(data->stdout_file)) {
            std::ofstream new_stdout(data->stdout_file.c_str());
        }
        if (!fs::exists(data->stderr_file)) {
            std::ofstream new_stderr(data->stderr_file.c_str());
        }

        return exit_handle(std::shared_ptr< exit_handle::impl >(
            new exit_handle::impl(
                handle,
                data->timer.fired() ? none : utils::make_optional(status),
                data->unprivileged_user,
                data->start_time, datetime::timestamp::now(),
                data->control_directory,
                data->stdout_file,
                data->stderr_file,
                data->state_owners,
                all_exec_data)));
    }