//===-- ExecuteFunction implementation for Unix-like Systems --------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "ExecuteFunction.h" #include "src/__support/macros/config.h" #include #include #include #include #include #include #include #include #include namespace LIBC_NAMESPACE_DECL { namespace testutils { bool ProcessStatus::exited_normally() { return WIFEXITED(platform_defined); } int ProcessStatus::get_exit_code() { assert(exited_normally() && "Abnormal termination, no exit code"); return WEXITSTATUS(platform_defined); } int ProcessStatus::get_fatal_signal() { if (exited_normally()) return 0; return WTERMSIG(platform_defined); } ProcessStatus invoke_in_subprocess(FunctionCaller *func, unsigned timeout_ms) { std::unique_ptr X(func); int pipe_fds[2]; if (::pipe(pipe_fds) == -1) return ProcessStatus::error("pipe(2) failed"); // Don't copy the buffers into the child process and print twice. std::cout.flush(); std::cerr.flush(); pid_t pid = ::fork(); if (pid == -1) return ProcessStatus::error("fork(2) failed"); if (!pid) { (*func)(); std::exit(0); } ::close(pipe_fds[1]); struct pollfd poll_fd { pipe_fds[0], 0, 0 }; // No events requested so this call will only return after the timeout or if // the pipes peer was closed, signaling the process exited. if (::poll(&poll_fd, 1, timeout_ms) == -1) return ProcessStatus::error("poll(2) failed"); // If the pipe wasn't closed by the child yet then timeout has expired. if (!(poll_fd.revents & POLLHUP)) { ::kill(pid, SIGKILL); return ProcessStatus::timed_out_ps(); } int wstatus = 0; // Wait on the pid of the subprocess here so it gets collected by the system // and doesn't turn into a zombie. pid_t status = ::waitpid(pid, &wstatus, 0); if (status == -1) return ProcessStatus::error("waitpid(2) failed"); assert(status == pid); return {wstatus}; } const char *signal_as_string(int signum) { return ::strsignal(signum); } } // namespace testutils } // namespace LIBC_NAMESPACE_DECL