xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/metal/process.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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