1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2023 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker // process.cpp:
7*8975f5c5SAndroid Build Coastguard Worker // Process manages a child process. This is largely copied from chrome.
8*8975f5c5SAndroid Build Coastguard Worker //
9*8975f5c5SAndroid Build Coastguard Worker
10*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/metal/process.h"
11*8975f5c5SAndroid Build Coastguard Worker
12*8975f5c5SAndroid Build Coastguard Worker #include <crt_externs.h>
13*8975f5c5SAndroid Build Coastguard Worker #include <fcntl.h>
14*8975f5c5SAndroid Build Coastguard Worker #include <mach/mach.h>
15*8975f5c5SAndroid Build Coastguard Worker #include <os/availability.h>
16*8975f5c5SAndroid Build Coastguard Worker #include <spawn.h>
17*8975f5c5SAndroid Build Coastguard Worker #include <string.h>
18*8975f5c5SAndroid Build Coastguard Worker #include <sys/resource.h>
19*8975f5c5SAndroid Build Coastguard Worker #include <sys/sysctl.h>
20*8975f5c5SAndroid Build Coastguard Worker #include <sys/time.h>
21*8975f5c5SAndroid Build Coastguard Worker #include <sys/wait.h>
22*8975f5c5SAndroid Build Coastguard Worker #include <unistd.h>
23*8975f5c5SAndroid Build Coastguard Worker
24*8975f5c5SAndroid Build Coastguard Worker #include "common/base/anglebase/logging.h"
25*8975f5c5SAndroid Build Coastguard Worker #include "common/debug.h"
26*8975f5c5SAndroid Build Coastguard Worker
27*8975f5c5SAndroid Build Coastguard Worker namespace rx
28*8975f5c5SAndroid Build Coastguard Worker {
29*8975f5c5SAndroid Build Coastguard Worker namespace mtl
30*8975f5c5SAndroid Build Coastguard Worker {
31*8975f5c5SAndroid Build Coastguard Worker namespace
32*8975f5c5SAndroid Build Coastguard Worker {
33*8975f5c5SAndroid Build Coastguard Worker
34*8975f5c5SAndroid Build Coastguard Worker // This code is copied from chrome's process launching code:
35*8975f5c5SAndroid Build Coastguard Worker // (base/process/launch_mac.cc).
36*8975f5c5SAndroid Build Coastguard Worker
37*8975f5c5SAndroid Build Coastguard Worker typedef pid_t ProcessId;
38*8975f5c5SAndroid Build Coastguard Worker constexpr ProcessId kNullProcessId = 0;
39*8975f5c5SAndroid Build Coastguard Worker
40*8975f5c5SAndroid Build Coastguard Worker // DPSXCHECK is a Debug Posix Spawn Check macro. The posix_spawn* family of
41*8975f5c5SAndroid Build Coastguard Worker // functions return an errno value, as opposed to setting errno directly. This
42*8975f5c5SAndroid Build Coastguard Worker // macro emulates a DPCHECK().
43*8975f5c5SAndroid Build Coastguard Worker #define DPSXCHECK(expr) \
44*8975f5c5SAndroid Build Coastguard Worker do \
45*8975f5c5SAndroid Build Coastguard Worker { \
46*8975f5c5SAndroid Build Coastguard Worker int rv = (expr); \
47*8975f5c5SAndroid Build Coastguard Worker DCHECK(rv == 0); \
48*8975f5c5SAndroid Build Coastguard Worker } while (0)
49*8975f5c5SAndroid Build Coastguard Worker
50*8975f5c5SAndroid Build Coastguard Worker // DCHECK(rv == 0) << #expr << ": -" << rv << " " << strerror(rv);
51*8975f5c5SAndroid Build Coastguard Worker
52*8975f5c5SAndroid Build Coastguard Worker class PosixSpawnAttr
53*8975f5c5SAndroid Build Coastguard Worker {
54*8975f5c5SAndroid Build Coastguard Worker public:
PosixSpawnAttr()55*8975f5c5SAndroid Build Coastguard Worker PosixSpawnAttr() { DPSXCHECK(posix_spawnattr_init(&attr_)); }
56*8975f5c5SAndroid Build Coastguard Worker
~PosixSpawnAttr()57*8975f5c5SAndroid Build Coastguard Worker ~PosixSpawnAttr() { DPSXCHECK(posix_spawnattr_destroy(&attr_)); }
58*8975f5c5SAndroid Build Coastguard Worker
get()59*8975f5c5SAndroid Build Coastguard Worker posix_spawnattr_t *get() { return &attr_; }
60*8975f5c5SAndroid Build Coastguard Worker
61*8975f5c5SAndroid Build Coastguard Worker private:
62*8975f5c5SAndroid Build Coastguard Worker posix_spawnattr_t attr_;
63*8975f5c5SAndroid Build Coastguard Worker };
64*8975f5c5SAndroid Build Coastguard Worker
65*8975f5c5SAndroid Build Coastguard Worker class PosixSpawnFileActions
66*8975f5c5SAndroid Build Coastguard Worker {
67*8975f5c5SAndroid Build Coastguard Worker public:
PosixSpawnFileActions()68*8975f5c5SAndroid Build Coastguard Worker PosixSpawnFileActions() { DPSXCHECK(posix_spawn_file_actions_init(&file_actions_)); }
69*8975f5c5SAndroid Build Coastguard Worker
70*8975f5c5SAndroid Build Coastguard Worker PosixSpawnFileActions(const PosixSpawnFileActions &) = delete;
71*8975f5c5SAndroid Build Coastguard Worker PosixSpawnFileActions &operator=(const PosixSpawnFileActions &) = delete;
72*8975f5c5SAndroid Build Coastguard Worker
~PosixSpawnFileActions()73*8975f5c5SAndroid Build Coastguard Worker ~PosixSpawnFileActions() { DPSXCHECK(posix_spawn_file_actions_destroy(&file_actions_)); }
74*8975f5c5SAndroid Build Coastguard Worker
Open(int filedes,const char * path,int mode)75*8975f5c5SAndroid Build Coastguard Worker void Open(int filedes, const char *path, int mode)
76*8975f5c5SAndroid Build Coastguard Worker {
77*8975f5c5SAndroid Build Coastguard Worker DPSXCHECK(posix_spawn_file_actions_addopen(&file_actions_, filedes, path, mode, 0));
78*8975f5c5SAndroid Build Coastguard Worker }
79*8975f5c5SAndroid Build Coastguard Worker
Dup2(int filedes,int newfiledes)80*8975f5c5SAndroid Build Coastguard Worker void Dup2(int filedes, int newfiledes)
81*8975f5c5SAndroid Build Coastguard Worker {
82*8975f5c5SAndroid Build Coastguard Worker DPSXCHECK(posix_spawn_file_actions_adddup2(&file_actions_, filedes, newfiledes));
83*8975f5c5SAndroid Build Coastguard Worker }
84*8975f5c5SAndroid Build Coastguard Worker
Inherit(int filedes)85*8975f5c5SAndroid Build Coastguard Worker void Inherit(int filedes)
86*8975f5c5SAndroid Build Coastguard Worker {
87*8975f5c5SAndroid Build Coastguard Worker DPSXCHECK(posix_spawn_file_actions_addinherit_np(&file_actions_, filedes));
88*8975f5c5SAndroid Build Coastguard Worker }
89*8975f5c5SAndroid Build Coastguard Worker
90*8975f5c5SAndroid Build Coastguard Worker #if TARGET_OS_OSX
Chdir(const char * path)91*8975f5c5SAndroid Build Coastguard Worker void Chdir(const char *path) API_AVAILABLE(macos(10.15))
92*8975f5c5SAndroid Build Coastguard Worker {
93*8975f5c5SAndroid Build Coastguard Worker DPSXCHECK(posix_spawn_file_actions_addchdir_np(&file_actions_, path));
94*8975f5c5SAndroid Build Coastguard Worker }
95*8975f5c5SAndroid Build Coastguard Worker #endif
96*8975f5c5SAndroid Build Coastguard Worker
get() const97*8975f5c5SAndroid Build Coastguard Worker const posix_spawn_file_actions_t *get() const { return &file_actions_; }
98*8975f5c5SAndroid Build Coastguard Worker
99*8975f5c5SAndroid Build Coastguard Worker private:
100*8975f5c5SAndroid Build Coastguard Worker posix_spawn_file_actions_t file_actions_;
101*8975f5c5SAndroid Build Coastguard Worker };
102*8975f5c5SAndroid Build Coastguard Worker
103*8975f5c5SAndroid Build Coastguard Worker // This is a slimmed down version of chrome's LaunchProcess().
LaunchProcess(const std::vector<std::string> & argv)104*8975f5c5SAndroid Build Coastguard Worker ProcessId LaunchProcess(const std::vector<std::string> &argv)
105*8975f5c5SAndroid Build Coastguard Worker {
106*8975f5c5SAndroid Build Coastguard Worker PosixSpawnAttr attr;
107*8975f5c5SAndroid Build Coastguard Worker
108*8975f5c5SAndroid Build Coastguard Worker DPSXCHECK(posix_spawnattr_setflags(attr.get(), POSIX_SPAWN_CLOEXEC_DEFAULT));
109*8975f5c5SAndroid Build Coastguard Worker
110*8975f5c5SAndroid Build Coastguard Worker PosixSpawnFileActions file_actions;
111*8975f5c5SAndroid Build Coastguard Worker
112*8975f5c5SAndroid Build Coastguard Worker // Process file descriptors for the child. By default, LaunchProcess will
113*8975f5c5SAndroid Build Coastguard Worker // open stdin to /dev/null and inherit stdout and stderr.
114*8975f5c5SAndroid Build Coastguard Worker bool inherit_stdout = true, inherit_stderr = true;
115*8975f5c5SAndroid Build Coastguard Worker bool null_stdin = true;
116*8975f5c5SAndroid Build Coastguard Worker
117*8975f5c5SAndroid Build Coastguard Worker if (null_stdin)
118*8975f5c5SAndroid Build Coastguard Worker {
119*8975f5c5SAndroid Build Coastguard Worker file_actions.Open(STDIN_FILENO, "/dev/null", O_RDONLY);
120*8975f5c5SAndroid Build Coastguard Worker }
121*8975f5c5SAndroid Build Coastguard Worker if (inherit_stdout)
122*8975f5c5SAndroid Build Coastguard Worker {
123*8975f5c5SAndroid Build Coastguard Worker file_actions.Inherit(STDOUT_FILENO);
124*8975f5c5SAndroid Build Coastguard Worker }
125*8975f5c5SAndroid Build Coastguard Worker if (inherit_stderr)
126*8975f5c5SAndroid Build Coastguard Worker {
127*8975f5c5SAndroid Build Coastguard Worker file_actions.Inherit(STDERR_FILENO);
128*8975f5c5SAndroid Build Coastguard Worker }
129*8975f5c5SAndroid Build Coastguard Worker
130*8975f5c5SAndroid Build Coastguard Worker std::vector<char *> argv_cstr;
131*8975f5c5SAndroid Build Coastguard Worker argv_cstr.reserve(argv.size() + 1);
132*8975f5c5SAndroid Build Coastguard Worker for (const auto &arg : argv)
133*8975f5c5SAndroid Build Coastguard Worker {
134*8975f5c5SAndroid Build Coastguard Worker argv_cstr.push_back(const_cast<char *>(arg.c_str()));
135*8975f5c5SAndroid Build Coastguard Worker }
136*8975f5c5SAndroid Build Coastguard Worker argv_cstr.push_back(nullptr);
137*8975f5c5SAndroid Build Coastguard Worker
138*8975f5c5SAndroid Build Coastguard Worker const bool clear_environment = false;
139*8975f5c5SAndroid Build Coastguard Worker char *empty_environ = nullptr;
140*8975f5c5SAndroid Build Coastguard Worker char **new_environ = clear_environment ? &empty_environ : *_NSGetEnviron();
141*8975f5c5SAndroid Build Coastguard Worker
142*8975f5c5SAndroid Build Coastguard Worker const char *executable_path = argv_cstr[0];
143*8975f5c5SAndroid Build Coastguard Worker
144*8975f5c5SAndroid Build Coastguard Worker pid_t pid;
145*8975f5c5SAndroid Build Coastguard Worker // Use posix_spawnp as some callers expect to have PATH consulted.
146*8975f5c5SAndroid Build Coastguard Worker int rv = posix_spawnp(&pid, executable_path, file_actions.get(), attr.get(), &argv_cstr[0],
147*8975f5c5SAndroid Build Coastguard Worker new_environ);
148*8975f5c5SAndroid Build Coastguard Worker
149*8975f5c5SAndroid Build Coastguard Worker if (rv != 0)
150*8975f5c5SAndroid Build Coastguard Worker {
151*8975f5c5SAndroid Build Coastguard Worker FATAL() << "posix_spawnp failed";
152*8975f5c5SAndroid Build Coastguard Worker return kNullProcessId;
153*8975f5c5SAndroid Build Coastguard Worker }
154*8975f5c5SAndroid Build Coastguard Worker
155*8975f5c5SAndroid Build Coastguard Worker return pid;
156*8975f5c5SAndroid Build Coastguard Worker }
157*8975f5c5SAndroid Build Coastguard Worker
GetParentProcessId(ProcessId process)158*8975f5c5SAndroid Build Coastguard Worker ProcessId GetParentProcessId(ProcessId process)
159*8975f5c5SAndroid Build Coastguard Worker {
160*8975f5c5SAndroid Build Coastguard Worker struct kinfo_proc info;
161*8975f5c5SAndroid Build Coastguard Worker size_t length = sizeof(struct kinfo_proc);
162*8975f5c5SAndroid Build Coastguard Worker int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, process};
163*8975f5c5SAndroid Build Coastguard Worker if (sysctl(mib, 4, &info, &length, NULL, 0) < 0)
164*8975f5c5SAndroid Build Coastguard Worker {
165*8975f5c5SAndroid Build Coastguard Worker FATAL() << "sysctl failed";
166*8975f5c5SAndroid Build Coastguard Worker return -1;
167*8975f5c5SAndroid Build Coastguard Worker }
168*8975f5c5SAndroid Build Coastguard Worker if (length == 0)
169*8975f5c5SAndroid Build Coastguard Worker return -1;
170*8975f5c5SAndroid Build Coastguard Worker return info.kp_eproc.e_ppid;
171*8975f5c5SAndroid Build Coastguard Worker }
172*8975f5c5SAndroid Build Coastguard Worker
173*8975f5c5SAndroid Build Coastguard Worker #define HANDLE_EINTR(x) \
174*8975f5c5SAndroid Build Coastguard Worker ({ \
175*8975f5c5SAndroid Build Coastguard Worker decltype(x) eintr_wrapper_result; \
176*8975f5c5SAndroid Build Coastguard Worker do \
177*8975f5c5SAndroid Build Coastguard Worker { \
178*8975f5c5SAndroid Build Coastguard Worker eintr_wrapper_result = (x); \
179*8975f5c5SAndroid Build Coastguard Worker } while (eintr_wrapper_result == -1 && errno == EINTR); \
180*8975f5c5SAndroid Build Coastguard Worker eintr_wrapper_result; \
181*8975f5c5SAndroid Build Coastguard Worker })
182*8975f5c5SAndroid Build Coastguard Worker
WaitForExitImpl(ProcessId pid,int & exit_code)183*8975f5c5SAndroid Build Coastguard Worker bool WaitForExitImpl(ProcessId pid, int &exit_code)
184*8975f5c5SAndroid Build Coastguard Worker {
185*8975f5c5SAndroid Build Coastguard Worker const ProcessId our_pid = getpid();
186*8975f5c5SAndroid Build Coastguard Worker ASSERT(pid != our_pid);
187*8975f5c5SAndroid Build Coastguard Worker
188*8975f5c5SAndroid Build Coastguard Worker const bool exited = (GetParentProcessId(pid) < 0);
189*8975f5c5SAndroid Build Coastguard Worker int status;
190*8975f5c5SAndroid Build Coastguard Worker const bool wait_result = HANDLE_EINTR(waitpid(pid, &status, 0)) > 0;
191*8975f5c5SAndroid Build Coastguard Worker if (!wait_result)
192*8975f5c5SAndroid Build Coastguard Worker {
193*8975f5c5SAndroid Build Coastguard Worker return exited;
194*8975f5c5SAndroid Build Coastguard Worker }
195*8975f5c5SAndroid Build Coastguard Worker if (WIFSIGNALED(status))
196*8975f5c5SAndroid Build Coastguard Worker {
197*8975f5c5SAndroid Build Coastguard Worker exit_code = -1;
198*8975f5c5SAndroid Build Coastguard Worker return true;
199*8975f5c5SAndroid Build Coastguard Worker }
200*8975f5c5SAndroid Build Coastguard Worker if (WIFEXITED(status))
201*8975f5c5SAndroid Build Coastguard Worker {
202*8975f5c5SAndroid Build Coastguard Worker exit_code = WEXITSTATUS(status);
203*8975f5c5SAndroid Build Coastguard Worker return true;
204*8975f5c5SAndroid Build Coastguard Worker }
205*8975f5c5SAndroid Build Coastguard Worker return exited;
206*8975f5c5SAndroid Build Coastguard Worker }
207*8975f5c5SAndroid Build Coastguard Worker
208*8975f5c5SAndroid Build Coastguard Worker } // namespace
209*8975f5c5SAndroid Build Coastguard Worker
Process(const std::vector<std::string> & argv)210*8975f5c5SAndroid Build Coastguard Worker Process::Process(const std::vector<std::string> &argv) : pid_(LaunchProcess(argv)) {}
211*8975f5c5SAndroid Build Coastguard Worker
~Process()212*8975f5c5SAndroid Build Coastguard Worker Process::~Process()
213*8975f5c5SAndroid Build Coastguard Worker {
214*8975f5c5SAndroid Build Coastguard Worker // TODO: figure out if should terminate/wait/whatever.
215*8975f5c5SAndroid Build Coastguard Worker }
216*8975f5c5SAndroid Build Coastguard Worker
WaitForExit(int & exit_code)217*8975f5c5SAndroid Build Coastguard Worker bool Process::WaitForExit(int &exit_code)
218*8975f5c5SAndroid Build Coastguard Worker {
219*8975f5c5SAndroid Build Coastguard Worker ASSERT(pid_ != kNullProcessId);
220*8975f5c5SAndroid Build Coastguard Worker return WaitForExitImpl(pid_, exit_code);
221*8975f5c5SAndroid Build Coastguard Worker }
222*8975f5c5SAndroid Build Coastguard Worker
DidLaunch() const223*8975f5c5SAndroid Build Coastguard Worker bool Process::DidLaunch() const
224*8975f5c5SAndroid Build Coastguard Worker {
225*8975f5c5SAndroid Build Coastguard Worker return pid_ != kNullProcessId;
226*8975f5c5SAndroid Build Coastguard Worker }
227*8975f5c5SAndroid Build Coastguard Worker
228*8975f5c5SAndroid Build Coastguard Worker } // namespace mtl
229*8975f5c5SAndroid Build Coastguard Worker } // namespace rx
230