6#if defined(DART_HOST_OS_MACOS)
11#include <crt_externs.h>
36int Process::global_exit_code_ = 0;
37Mutex* Process::global_exit_code_mutex_ =
nullptr;
41#if !defined(DART_HOST_OS_IOS)
49 ProcessInfo(pid_t pid, intptr_t fd) : pid_(pid), fd_(fd) {}
51 int closed = close(fd_);
53 FATAL(
"Failed to close process exit code pipe");
56 pid_t pid() {
return pid_; }
57 intptr_t fd() {
return fd_; }
58 ProcessInfo*
next() {
return next_; }
59 void set_next(ProcessInfo*
info) { next_ =
info; }
71class ProcessInfoList {
76 static void AddProcess(pid_t pid, intptr_t fd) {
77 MutexLocker locker(mutex_);
78 ProcessInfo*
info =
new ProcessInfo(pid, fd);
79 info->set_next(active_processes_);
80 active_processes_ =
info;
83 static intptr_t LookupProcessExitFd(pid_t pid) {
84 MutexLocker locker(mutex_);
85 ProcessInfo* current = active_processes_;
86 while (current !=
nullptr) {
87 if (current->pid() == pid) {
90 current = current->next();
95 static void RemoveProcess(pid_t pid) {
96 MutexLocker locker(mutex_);
97 ProcessInfo*
prev =
nullptr;
98 ProcessInfo* current = active_processes_;
99 while (current !=
nullptr) {
100 if (current->pid() == pid) {
101 if (
prev ==
nullptr) {
102 active_processes_ = current->next();
104 prev->set_next(current->next());
110 current = current->next();
117 static ProcessInfo* active_processes_;
120 static Mutex* mutex_;
126ProcessInfo* ProcessInfoList::active_processes_ =
nullptr;
127Mutex* ProcessInfoList::mutex_ =
nullptr;
133class ExitCodeHandler {
139 static void ProcessStarted() {
142 MonitorLocker locker(monitor_);
153 Thread::Start(
"dart:io Process.start", ExitCodeHandlerEntry, 0);
155 FATAL(
"Failed to start exit code handler worker thread %d",
result);
161 static void TerminateExitCodeThread() {
162 MonitorLocker locker(monitor_);
179 while (!terminate_done_) {
187 static void ExitCodeHandlerEntry(
uword param) {
192 MonitorLocker locker(monitor_);
193 while (running_ && process_count_ == 0) {
197 terminate_done_ =
true;
206 if (WIFEXITED(status)) {
207 exit_code = WEXITSTATUS(status);
209 if (WIFSIGNALED(status)) {
210 exit_code = WTERMSIG(status);
213 intptr_t exit_code_fd = ProcessInfoList::LookupProcessExitFd(pid);
214 if (exit_code_fd != 0) {
215 int message[2] = {exit_code, negative};
223 FATAL(
"Failed to write entire process exit message");
224 }
else if ((
result == -1) && (errno != EPIPE)) {
225 FATAL(
"Failed to write exit code: %d", errno);
227 ProcessInfoList::RemoveProcess(pid);
229 MonitorLocker locker(monitor_);
233 }
else if (pid < 0) {
234 FATAL(
"Wait for process exit failed: %d", errno);
239 static bool terminate_done_;
240 static int process_count_;
241 static bool running_;
242 static Monitor* monitor_;
248bool ExitCodeHandler::running_ =
false;
249int ExitCodeHandler::process_count_ = 0;
250bool ExitCodeHandler::terminate_done_ =
false;
251Monitor* ExitCodeHandler::monitor_ =
nullptr;
253class ProcessStarter {
255 ProcessStarter(
const char*
path,
257 intptr_t arguments_length,
258 const char* working_directory,
260 intptr_t environment_length,
266 intptr_t* exit_event,
267 char** os_error_message)
269 working_directory_(working_directory),
275 exit_event_(exit_event),
276 os_error_message_(os_error_message) {
283 exec_control_[0] = -1;
284 exec_control_[1] = -1;
287 (arguments_length + 2) *
sizeof(*program_arguments_)));
288 program_arguments_[0] =
const_cast<char*
>(path_);
289 for (
int i = 0;
i < arguments_length;
i++) {
290 program_arguments_[
i + 1] = arguments[
i];
292 program_arguments_[arguments_length + 1] =
nullptr;
294 program_environment_ =
nullptr;
297 (environment_length + 1) *
sizeof(*program_environment_)));
298 for (
int i = 0;
i < environment_length;
i++) {
301 program_environment_[environment_length] =
nullptr;
307 int err = CreatePipes();
316 return CleanupAndReturnError();
317 }
else if (pid == 0) {
328 ExitCodeHandler::ProcessStarted();
329 err = RegisterProcess(pid);
341 if (bytes_written !=
sizeof(msg)) {
342 return CleanupAndReturnError();
346 close(exec_control_[1]);
347 exec_control_[1] = -1;
349 err = ReadExecResult();
351 err = ReadDetachedExecResult(&pid);
353 close(exec_control_[0]);
354 exec_control_[0] = -1;
377 *out_ = write_out_[1];
378 close(write_out_[0]);
380 *err_ = read_err_[0];
386 ASSERT(write_out_[0] == -1);
387 ASSERT(write_out_[1] == -1);
388 ASSERT(read_err_[0] == -1);
389 ASSERT(read_err_[1] == -1);
391 ASSERT(exec_control_[0] == -1);
392 ASSERT(exec_control_[1] == -1);
403 return CleanupAndReturnError();
412 return CleanupAndReturnError();
421 return CleanupAndReturnError();
428 return CleanupAndReturnError();
441 if (bytes_read !=
sizeof(msg)) {
442 perror(
"Failed receiving notification message");
448 ExecDetachedProcess();
469 if (working_directory_ !=
nullptr &&
474 if (program_environment_ !=
nullptr) {
477 char*** environ = _NSGetEnviron();
478 *environ = program_environment_;
481 execvp(path_,
const_cast<char* const*
>(program_arguments_));
485 void ExecDetachedProcess() {
487 ASSERT(write_out_[0] == -1);
488 ASSERT(write_out_[1] == -1);
489 ASSERT(read_err_[0] == -1);
490 ASSERT(read_err_[1] == -1);
505 }
else if (pid == 0) {
514 }
else if (pid == 0) {
518 SetupDetachedWithStdio();
521 if ((working_directory_ !=
nullptr) &&
526 if (program_environment_ !=
nullptr) {
529 char*** environ = _NSGetEnviron();
530 *environ = program_environment_;
535 execvp(path_,
const_cast<char* const*
>(program_arguments_));
550 int RegisterProcess(pid_t pid) {
555 return CleanupAndReturnError();
560 ProcessInfoList::AddProcess(pid, event_fds[1]);
561 *exit_event_ = event_fds[0];
566 int ReadExecResult() {
573 sizeof(child_errno));
574 if (bytes_read ==
sizeof(child_errno)) {
577 }
else if (bytes_read == -1) {
583 int ReadDetachedExecResult(pid_t* pid) {
592 if (bytes_read ==
sizeof(
int)) {
594 }
else if (bytes_read == 2 *
sizeof(
int)) {
599 }
else if (bytes_read == -1) {
605 void SetupDetached() {
609 int max_fds = sysconf(_SC_OPEN_MAX);
611 max_fds = _POSIX_OPEN_MAX;
613 for (
int fd = 0; fd < max_fds; fd++) {
614 if (fd != exec_control_[1]) {
623 if (fd != STDIN_FILENO) {
636 void SetupDetachedWithStdio() {
640 int max_fds = sysconf(_SC_OPEN_MAX);
642 max_fds = _POSIX_OPEN_MAX;
644 for (
int fd = 0; fd < max_fds; fd++) {
645 if ((fd != exec_control_[1]) && (fd != write_out_[0]) &&
646 (fd != read_in_[1]) && (fd != read_err_[1])) {
654 close(write_out_[0]);
667 int CleanupAndReturnError() {
668 int actual_errno = errno;
671 if (actual_errno == 0) {
672 actual_errno = EPERM;
674 SetChildOsErrorMessage();
679 void SetChildOsErrorMessage() {
683 *os_error_message_ = error_message;
686 void ReportChildError() {
689 int child_errno = errno;
694 sizeof(child_errno));
695 if (bytes_written ==
sizeof(child_errno)) {
697 strlen(os_error_message) + 1);
699 close(exec_control_[1]);
704 void ReportPid(
int pid) {
709 ASSERT(bytes_written ==
sizeof(
int));
713 void ReadChildError() {
714 const int kMaxMessageSize = 256;
718 message[kMaxMessageSize - 1] =
'\0';
722 ASSERT(*os_error_message_ ==
nullptr);
726 void ClosePipe(
int* fds) {
727 for (
int i = 0;
i < 2;
i++) {
735 void CloseAllPipes() {
736 ClosePipe(exec_control_);
738 ClosePipe(read_err_);
739 ClosePipe(write_out_);
745 int exec_control_[2];
747 char** program_arguments_;
748 char** program_environment_;
751 const char* working_directory_;
757 intptr_t* exit_event_;
758 char** os_error_message_;
768 intptr_t arguments_length,
769 const char* working_directory,
771 intptr_t environment_length,
777 intptr_t* exit_event,
778 char** os_error_message) {
779#if defined(DART_HOST_OS_IOS)
782 ProcessStarter starter(
path, arguments, arguments_length, working_directory,
784 id, exit_event, os_error_message);
785 return starter.Start();
789#if !defined(DART_HOST_OS_IOS)
790static bool CloseProcessBuffers(
struct pollfd* fds,
int alive) {
792 for (
int i = 0;
i < alive;
i++) {
806#if defined(DART_HOST_OS_IOS)
822 struct pollfd fds[3];
825 fds[2].fd = exit_event;
827 for (
int i = 0;
i < 3;
i++) {
828 fds[
i].events = POLLIN;
835 return CloseProcessBuffers(fds, alive);
839 for (
int i = 0;
i < alive;
i++) {
841 if ((fds[
i].revents & (POLLNVAL | POLLERR)) != 0) {
842 return CloseProcessBuffers(fds, alive);
844 if ((fds[
i].revents & POLLIN) != 0) {
849 if (fds[
i].fd ==
out) {
850 if (!out_data.Read(
out, avail)) {
851 return CloseProcessBuffers(fds, alive);
853 }
else if (fds[
i].fd == err) {
854 if (!err_data.Read(err, avail)) {
855 return CloseProcessBuffers(fds, alive);
857 }
else if (fds[
i].fd == exit_event) {
862 return CloseProcessBuffers(fds, alive);
870 if (((fds[
i].revents & POLLHUP) != 0) ||
871 (((fds[
i].revents & POLLIN) != 0) && (avail == 0))) {
886 result->set_stdout_data(out_data.GetData());
887 result->set_stderr_data(err_data.GetData());
892 intptr_t exit_code = exit_code_data.ints[0];
893 intptr_t negative = exit_code_data.ints[1];
895 exit_code = -exit_code;
897 result->set_exit_code(exit_code);
903static int SignalMap(intptr_t
id) {
968#if defined(DART_HOST_OS_IOS)
976#if !defined(DART_HOST_OS_IOS)
977 ExitCodeHandler::TerminateExitCodeThread();
982 return static_cast<intptr_t
>(getpid());
986 struct mach_task_basic_info
info;
987 mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
989 task_info(mach_task_self(), MACH_TASK_BASIC_INFO,
990 reinterpret_cast<task_info_t
>(&
info), &infoCount);
991 if (
result != KERN_SUCCESS) {
994 return info.resident_size;
1000 int r = getrusage(RUSAGE_SELF, &
usage);
1004 return usage.ru_maxrss;
1007static Mutex* signal_mutex =
nullptr;
1008static SignalInfo* signal_handlers =
nullptr;
1009static constexpr int kSignalsCount = 7;
1010static const int kSignals[kSignalsCount] = {
1011 SIGHUP, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGWINCH,
1020 MutexLocker lock(signal_mutex);
1021 const SignalInfo* handler = signal_handlers;
1022 while (handler !=
nullptr) {
1023 if (handler->signal() == signal) {
1027 handler = handler->next();
1032 signal = SignalMap(signal);
1037 for (
int i = 0;
i < kSignalsCount;
i++) {
1038 if (kSignals[
i] == signal) {
1056 ThreadSignalBlocker blocker(kSignalsCount, kSignals);
1057 MutexLocker lock(signal_mutex);
1058 SignalInfo* handler = signal_handlers;
1061 while (handler !=
nullptr) {
1062 if (handler->signal() == signal) {
1063 oldact_handler = handler->oldact();
1067 handler = handler->next();
1070 struct sigaction act = {};
1072 sigemptyset(&act.sa_mask);
1073 for (
int i = 0;
i < kSignalsCount;
i++) {
1074 sigaddset(&act.sa_mask, kSignals[
i]);
1076 struct sigaction oldact = {};
1083 oldact_handler = oldact.sa_handler;
1086 new SignalInfo(fds[1], signal, oldact_handler, signal_handlers);
1091 signal = SignalMap(signal);
1095 ThreadSignalBlocker blocker(kSignalsCount, kSignals);
1096 MutexLocker lock(signal_mutex);
1097 SignalInfo* handler = signal_handlers;
1099 bool any_removed =
false;
1100 bool any_remaining =
false;
1101 while (handler !=
nullptr) {
1103 if (handler->signal() == signal) {
1105 if (signal_handlers == handler) {
1106 signal_handlers = handler->next();
1110 oldact_handler = handler->oldact();
1113 any_remaining =
true;
1116 SignalInfo*
next = handler->next();
1122 if (any_removed && !any_remaining) {
1123 struct sigaction act = {};
1124 act.sa_handler = oldact_handler;
1130 ThreadSignalBlocker blocker(kSignalsCount, kSignals);
1131 MutexLocker lock(signal_mutex);
1132 SignalInfo* handler = signal_handlers;
1134 bool any_remaining =
false;
1135 intptr_t signal = -1;
1136 while (handler !=
nullptr) {
1138 if (handler->fd() == fd) {
1140 if (signal_handlers == handler) {
1141 signal_handlers = handler->next();
1145 signal = handler->signal();
1147 any_remaining =
true;
1150 SignalInfo*
next = handler->next();
1156 if ((signal != -1) && !any_remaining) {
1157 struct sigaction act = {};
1158 act.sa_handler = oldact_handler;
1163#if !defined(DART_HOST_OS_IOS)
1165 active_processes_ =
nullptr;
1166 ASSERT(ProcessInfoList::mutex_ ==
nullptr);
1167 ProcessInfoList::mutex_ =
new Mutex();
1171 ASSERT(ProcessInfoList::mutex_ !=
nullptr);
1172 delete ProcessInfoList::mutex_;
1173 ProcessInfoList::mutex_ =
nullptr;
1179 terminate_done_ =
false;
1180 ASSERT(ExitCodeHandler::monitor_ ==
nullptr);
1181 ExitCodeHandler::monitor_ =
new Monitor();
1185 ASSERT(ExitCodeHandler::monitor_ !=
nullptr);
1186 delete ExitCodeHandler::monitor_;
1187 ExitCodeHandler::monitor_ =
nullptr;
1192#if !defined(DART_HOST_OS_IOS)
1197 ASSERT(signal_mutex ==
nullptr);
1198 signal_mutex =
new Mutex();
1199 signal_handlers =
nullptr;
1201 ASSERT(Process::global_exit_code_mutex_ ==
nullptr);
1202 Process::global_exit_code_mutex_ =
new Mutex();
1208 ASSERT(signal_mutex !=
nullptr);
1209 delete signal_mutex;
1210 signal_mutex =
nullptr;
1212 ASSERT(Process::global_exit_code_mutex_ !=
nullptr);
1213 delete Process::global_exit_code_mutex_;
1214 Process::global_exit_code_mutex_ =
nullptr;
1216#if !defined(DART_HOST_OS_IOS)
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
static float next(float f)
static float prev(float f)
static bool read(SkStream *stream, void *buffer, size_t amount)
static const size_t kBufferSize
#define DEBUG_ASSERT(cond)
static char * StrError(int err, char *buffer, size_t bufsize)
static char * ScopedCString(intptr_t length)
static intptr_t AvailableBytes(intptr_t fd)
static bool SetCloseOnExec(intptr_t fd)
static bool SetNonBlocking(intptr_t fd)
static ssize_t ReadFromBlocking(int fd, void *buffer, size_t count)
static ssize_t WriteToBlocking(int fd, const void *buffer, size_t count)
static constexpr int64_t kNoTimeout
static bool ModeIsAttached(ProcessStartMode mode)
static void ClearSignalHandler(intptr_t signal, Dart_Port port)
static void ClearSignalHandlerByFd(intptr_t fd, Dart_Port port)
static bool ModeHasStdio(ProcessStartMode mode)
static int64_t CurrentRSS()
static intptr_t CurrentProcessId()
static void TerminateExitCodeHandler()
static bool Wait(intptr_t id, intptr_t in, intptr_t out, intptr_t err, intptr_t exit_handler, ProcessResult *result)
static bool Kill(intptr_t id, int signal)
static intptr_t SetSignalHandler(intptr_t signal)
void(* ExitHook)(int64_t exit_code)
static void ClearAllSignalHandlers()
static int Start(Namespace *namespc, const char *path, char *arguments[], intptr_t arguments_length, const char *working_directory, char *environment[], intptr_t environment_length, ProcessStartMode mode, intptr_t *in, intptr_t *out, intptr_t *err, intptr_t *id, intptr_t *exit_handler, char **os_error_message)
static int Start(const char *name, ThreadStartFunction function, uword parameters)
void(* sa_handler_t)(int)
static dart::SimpleHashMap * environment
DART_EXPORT uint8_t * Dart_ScopeAllocate(intptr_t size)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service port
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
static void SignalHandler(int signal)
#define NO_RETRY_EXPECTED(expression)
#define VOID_TEMP_FAILURE_RETRY(expression)
#define VOID_NO_RETRY_EXPECTED(expression)
#define TEMP_FAILURE_RETRY(expression)
static void usage(char *argv0)
void write(SkWStream *wStream, const T &text)