xref: /llvm-project/libc/test/UnitTest/ExecuteFunctionUnix.cpp (revision 9426fdd4cbd6812b69c218b865f184cb25342be4)
1e3645eadSSiva Chandra Reddy //===-- ExecuteFunction implementation for Unix-like Systems --------------===//
2e3645eadSSiva Chandra Reddy //
3e3645eadSSiva Chandra Reddy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e3645eadSSiva Chandra Reddy // See https://llvm.org/LICENSE.txt for license information.
5e3645eadSSiva Chandra Reddy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e3645eadSSiva Chandra Reddy //
7e3645eadSSiva Chandra Reddy //===----------------------------------------------------------------------===//
8e3645eadSSiva Chandra Reddy 
9e3645eadSSiva Chandra Reddy #include "ExecuteFunction.h"
105ff3ff33SPetr Hosek #include "src/__support/macros/config.h"
110efb376cSNick Desaulniers #include "test/UnitTest/ExecuteFunction.h" // FunctionCaller
120efb376cSNick Desaulniers #include <assert.h>
13e3645eadSSiva Chandra Reddy #include <poll.h>
14e3645eadSSiva Chandra Reddy #include <signal.h>
150efb376cSNick Desaulniers #include <stdio.h>
160efb376cSNick Desaulniers #include <stdlib.h>
170efb376cSNick Desaulniers #include <string.h>
18e3645eadSSiva Chandra Reddy #include <sys/wait.h>
19e3645eadSSiva Chandra Reddy #include <unistd.h>
20e3645eadSSiva Chandra Reddy 
215ff3ff33SPetr Hosek namespace LIBC_NAMESPACE_DECL {
22e3645eadSSiva Chandra Reddy namespace testutils {
23e3645eadSSiva Chandra Reddy 
24e3645eadSSiva Chandra Reddy bool ProcessStatus::exited_normally() { return WIFEXITED(platform_defined); }
25e3645eadSSiva Chandra Reddy 
26e3645eadSSiva Chandra Reddy int ProcessStatus::get_exit_code() {
27e3645eadSSiva Chandra Reddy   assert(exited_normally() && "Abnormal termination, no exit code");
28e3645eadSSiva Chandra Reddy   return WEXITSTATUS(platform_defined);
29e3645eadSSiva Chandra Reddy }
30e3645eadSSiva Chandra Reddy 
31e3645eadSSiva Chandra Reddy int ProcessStatus::get_fatal_signal() {
32e3645eadSSiva Chandra Reddy   if (exited_normally())
33e3645eadSSiva Chandra Reddy     return 0;
34e3645eadSSiva Chandra Reddy   return WTERMSIG(platform_defined);
35e3645eadSSiva Chandra Reddy }
36e3645eadSSiva Chandra Reddy 
37e3645eadSSiva Chandra Reddy ProcessStatus invoke_in_subprocess(FunctionCaller *func, unsigned timeout_ms) {
38e3645eadSSiva Chandra Reddy   int pipe_fds[2];
393caa68a0SNick Desaulniers   if (::pipe(pipe_fds) == -1) {
40*9426fdd4SNick Desaulniers     delete func;
41e3645eadSSiva Chandra Reddy     return ProcessStatus::error("pipe(2) failed");
423caa68a0SNick Desaulniers   }
43e3645eadSSiva Chandra Reddy 
44e3645eadSSiva Chandra Reddy   // Don't copy the buffers into the child process and print twice.
450efb376cSNick Desaulniers   ::fflush(stderr);
460efb376cSNick Desaulniers   ::fflush(stdout);
47e3645eadSSiva Chandra Reddy   pid_t pid = ::fork();
483caa68a0SNick Desaulniers   if (pid == -1) {
49*9426fdd4SNick Desaulniers     delete func;
50e3645eadSSiva Chandra Reddy     return ProcessStatus::error("fork(2) failed");
513caa68a0SNick Desaulniers   }
52e3645eadSSiva Chandra Reddy 
53e3645eadSSiva Chandra Reddy   if (!pid) {
54e3645eadSSiva Chandra Reddy     (*func)();
55*9426fdd4SNick Desaulniers     delete func;
560efb376cSNick Desaulniers     ::exit(0);
57e3645eadSSiva Chandra Reddy   }
58e3645eadSSiva Chandra Reddy   ::close(pipe_fds[1]);
59e3645eadSSiva Chandra Reddy 
60e3645eadSSiva Chandra Reddy   struct pollfd poll_fd {
61e3645eadSSiva Chandra Reddy     pipe_fds[0], 0, 0
62e3645eadSSiva Chandra Reddy   };
63e3645eadSSiva Chandra Reddy   // No events requested so this call will only return after the timeout or if
64e3645eadSSiva Chandra Reddy   // the pipes peer was closed, signaling the process exited.
653caa68a0SNick Desaulniers   if (::poll(&poll_fd, 1, timeout_ms) == -1) {
66*9426fdd4SNick Desaulniers     delete func;
67e3645eadSSiva Chandra Reddy     return ProcessStatus::error("poll(2) failed");
683caa68a0SNick Desaulniers   }
69e3645eadSSiva Chandra Reddy   // If the pipe wasn't closed by the child yet then timeout has expired.
70e3645eadSSiva Chandra Reddy   if (!(poll_fd.revents & POLLHUP)) {
71e3645eadSSiva Chandra Reddy     ::kill(pid, SIGKILL);
72*9426fdd4SNick Desaulniers     delete func;
73e3645eadSSiva Chandra Reddy     return ProcessStatus::timed_out_ps();
74e3645eadSSiva Chandra Reddy   }
75e3645eadSSiva Chandra Reddy 
76e3645eadSSiva Chandra Reddy   int wstatus = 0;
77e3645eadSSiva Chandra Reddy   // Wait on the pid of the subprocess here so it gets collected by the system
78e3645eadSSiva Chandra Reddy   // and doesn't turn into a zombie.
79e3645eadSSiva Chandra Reddy   pid_t status = ::waitpid(pid, &wstatus, 0);
803caa68a0SNick Desaulniers   if (status == -1) {
81*9426fdd4SNick Desaulniers     delete func;
82e3645eadSSiva Chandra Reddy     return ProcessStatus::error("waitpid(2) failed");
833caa68a0SNick Desaulniers   }
84e3645eadSSiva Chandra Reddy   assert(status == pid);
85*9426fdd4SNick Desaulniers   delete func;
86e3645eadSSiva Chandra Reddy   return {wstatus};
87e3645eadSSiva Chandra Reddy }
88e3645eadSSiva Chandra Reddy 
89e3645eadSSiva Chandra Reddy const char *signal_as_string(int signum) { return ::strsignal(signum); }
90e3645eadSSiva Chandra Reddy 
91e3645eadSSiva Chandra Reddy } // namespace testutils
925ff3ff33SPetr Hosek } // namespace LIBC_NAMESPACE_DECL
93