6#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
16#include <sys/resource.h>
37int Process::global_exit_code_ = 0;
38Mutex* Process::global_exit_code_mutex_ =
nullptr;
47 ProcessInfo(pid_t pid, intptr_t fd) : pid_(pid), fd_(fd) {}
49 int closed = close(fd_);
51 FATAL(
"Failed to close process exit code pipe");
54 pid_t pid() {
return pid_; }
55 intptr_t fd() {
return fd_; }
56 ProcessInfo*
next() {
return next_; }
57 void set_next(ProcessInfo*
info) { next_ =
info; }
69class ProcessInfoList {
74 static void AddProcess(pid_t pid, intptr_t fd) {
75 MutexLocker locker(mutex_);
76 ProcessInfo*
info =
new ProcessInfo(pid, fd);
77 info->set_next(active_processes_);
78 active_processes_ =
info;
81 static intptr_t LookupProcessExitFd(pid_t pid) {
82 MutexLocker locker(mutex_);
83 ProcessInfo* current = active_processes_;
84 while (current !=
nullptr) {
85 if (current->pid() == pid) {
88 current = current->next();
93 static void RemoveProcess(pid_t pid) {
94 MutexLocker locker(mutex_);
95 ProcessInfo*
prev =
nullptr;
96 ProcessInfo* current = active_processes_;
97 while (current !=
nullptr) {
98 if (current->pid() == pid) {
99 if (
prev ==
nullptr) {
100 active_processes_ = current->next();
102 prev->set_next(current->next());
108 current = current->next();
115 static ProcessInfo* active_processes_;
118 static Mutex* mutex_;
124ProcessInfo* ProcessInfoList::active_processes_ =
nullptr;
125Mutex* ProcessInfoList::mutex_ =
nullptr;
131class ExitCodeHandler {
137 static void ProcessStarted() {
140 MonitorLocker locker(monitor_);
151 Thread::Start(
"dart:io Process.start", ExitCodeHandlerEntry, 0);
153 FATAL(
"Failed to start exit code handler worker thread %d",
result);
159 static void TerminateExitCodeThread() {
160 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(Namespace* namespc,
258 intptr_t arguments_length,
259 const char* working_directory,
261 intptr_t environment_length,
267 intptr_t* exit_event,
268 char** os_error_message)
271 working_directory_(working_directory),
277 exit_event_(exit_event),
278 os_error_message_(os_error_message) {
285 exec_control_[0] = -1;
286 exec_control_[1] = -1;
289 (arguments_length + 2) *
sizeof(*program_arguments_)));
290 program_arguments_[0] =
const_cast<char*
>(path_);
291 for (
int i = 0;
i < arguments_length;
i++) {
292 program_arguments_[
i + 1] = arguments[
i];
294 program_arguments_[arguments_length + 1] =
nullptr;
296 program_environment_ =
nullptr;
299 (environment_length + 1) *
sizeof(*program_environment_)));
300 for (
int i = 0;
i < environment_length;
i++) {
303 program_environment_[environment_length] =
nullptr;
309 int err = CreatePipes();
318 return CleanupAndReturnError();
319 }
else if (pid == 0) {
330 ExitCodeHandler::ProcessStarted();
331 err = RegisterProcess(pid);
343 if (bytes_written !=
sizeof(msg)) {
344 return CleanupAndReturnError();
348 close(exec_control_[1]);
349 exec_control_[1] = -1;
351 err = ReadExecResult();
353 err = ReadDetachedExecResult(&pid);
355 close(exec_control_[0]);
356 exec_control_[0] = -1;
379 *out_ = write_out_[1];
380 close(write_out_[0]);
382 *err_ = read_err_[0];
388 ASSERT(write_out_[0] == -1);
389 ASSERT(write_out_[1] == -1);
390 ASSERT(read_err_[0] == -1);
391 ASSERT(read_err_[1] == -1);
393 ASSERT(exec_control_[0] == -1);
394 ASSERT(exec_control_[1] == -1);
401 static constexpr int kErrorBufferSize = 1024;
407 return CleanupAndReturnError();
414 return CleanupAndReturnError();
421 return CleanupAndReturnError();
426 return CleanupAndReturnError();
437 if (bytes_read !=
sizeof(msg)) {
438 perror(
"Failed receiving notification message");
444 ExecDetachedProcess();
453 bool FindPathInNamespace(
char* realpath, intptr_t realpath_size) {
458 strncpy(realpath, path_, realpath_size);
459 realpath[realpath_size - 1] =
'\0';
462 NamespaceScope ns(namespc_, path_);
469 snprintf(procpath,
PATH_MAX,
"/proc/self/fd/%d", fd);
498 if (working_directory_ !=
nullptr &&
503 if (program_environment_ !=
nullptr) {
504 environ = program_environment_;
508 if (!FindPathInNamespace(realpath,
PATH_MAX)) {
512 execvp(realpath,
const_cast<char* const*
>(program_arguments_));
516 void ExecDetachedProcess() {
518 ASSERT(write_out_[0] == -1);
519 ASSERT(write_out_[1] == -1);
520 ASSERT(read_err_[0] == -1);
521 ASSERT(read_err_[1] == -1);
536 }
else if (pid == 0) {
545 }
else if (pid == 0) {
549 SetupDetachedWithStdio();
552 if ((working_directory_ !=
nullptr) &&
556 if (program_environment_ !=
nullptr) {
557 environ = program_environment_;
563 if (!FindPathInNamespace(realpath,
PATH_MAX)) {
568 execvp(realpath,
const_cast<char* const*
>(program_arguments_));
583 int RegisterProcess(pid_t pid) {
588 return CleanupAndReturnError();
591 ProcessInfoList::AddProcess(pid, event_fds[1]);
592 *exit_event_ = event_fds[0];
597 int ReadExecResult() {
604 sizeof(child_errno));
605 if (bytes_read ==
sizeof(child_errno)) {
608 }
else if (bytes_read == -1) {
614 int ReadDetachedExecResult(pid_t* pid) {
623 if (bytes_read ==
sizeof(
int)) {
625 }
else if (bytes_read == 2 *
sizeof(
int)) {
630 }
else if (bytes_read == -1) {
636 void SetupDetached() {
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]) {
654 if (fd != STDIN_FILENO) {
667 void SetupDetachedWithStdio() {
671 int max_fds = sysconf(_SC_OPEN_MAX);
673 max_fds = _POSIX_OPEN_MAX;
675 for (
int fd = 0; fd < max_fds; fd++) {
676 if ((fd != exec_control_[1]) && (fd != write_out_[0]) &&
677 (fd != read_in_[1]) && (fd != read_err_[1])) {
685 close(write_out_[0]);
698 int CleanupAndReturnError() {
699 int actual_errno = errno;
702 if (actual_errno == 0) {
703 actual_errno = EPERM;
705 SetChildOsErrorMessage();
710 void SetChildOsErrorMessage() {
713 *os_error_message_ = error_message;
716 void ReportChildError() {
719 int child_errno = errno;
720 char error_buf[kErrorBufferSize];
721 char* os_error_message =
724 sizeof(child_errno));
725 if (bytes_written ==
sizeof(child_errno)) {
727 strlen(os_error_message) + 1);
729 close(exec_control_[1]);
737 void ReportPid(
int pid) {
742 ASSERT(bytes_written ==
sizeof(
int));
746 void ReadChildError() {
750 message[kErrorBufferSize - 1] =
'\0';
754 ASSERT(*os_error_message_ ==
nullptr);
758 void ClosePipe(
int* fds) {
759 for (
int i = 0;
i < 2;
i++) {
767 void CloseAllPipes() {
768 ClosePipe(exec_control_);
770 ClosePipe(read_err_);
771 ClosePipe(write_out_);
777 int exec_control_[2];
779 char** program_arguments_;
780 char** program_environment_;
784 const char* working_directory_;
790 intptr_t* exit_event_;
791 char** os_error_message_;
800 intptr_t arguments_length,
801 const char* working_directory,
803 intptr_t environment_length,
809 intptr_t* exit_event,
810 char** os_error_message) {
811 ProcessStarter starter(namespc,
path, arguments, arguments_length,
812 working_directory,
environment, environment_length,
813 mode, in,
out, err,
id, exit_event, os_error_message);
814 return starter.Start();
817static bool CloseProcessBuffers(
struct pollfd* fds,
int alive) {
819 for (
int i = 0;
i < alive;
i++) {
845 struct pollfd fds[3];
848 fds[2].fd = exit_event;
850 for (
int i = 0;
i < 3;
i++) {
851 fds[
i].events = POLLIN;
858 return CloseProcessBuffers(fds, alive);
862 for (
int i = 0;
i < alive;
i++) {
863 if ((fds[
i].revents & (POLLNVAL | POLLERR)) != 0) {
864 return CloseProcessBuffers(fds, alive);
866 if ((fds[
i].revents & POLLIN) != 0) {
868 if (fds[
i].fd ==
out) {
869 if (!out_data.Read(
out, avail)) {
870 return CloseProcessBuffers(fds, alive);
872 }
else if (fds[
i].fd == err) {
873 if (!err_data.Read(err, avail)) {
874 return CloseProcessBuffers(fds, alive);
876 }
else if (fds[
i].fd == exit_event) {
881 return CloseProcessBuffers(fds, alive);
888 if ((fds[
i].revents & POLLHUP) != 0) {
903 result->set_stdout_data(out_data.GetData());
904 result->set_stderr_data(err_data.GetData());
909 intptr_t exit_code = exit_code_data.ints[0];
910 intptr_t negative = exit_code_data.ints[1];
912 exit_code = -exit_code;
914 result->set_exit_code(exit_code);
924 ExitCodeHandler::TerminateExitCodeThread();
928 return static_cast<intptr_t
>(getpid());
931static void SaveErrorAndClose(FILE*
file) {
932 int actual_errno = errno;
934 errno = actual_errno;
941 FILE* statm = fopen(
"/proc/self/statm",
"r");
942 if (statm ==
nullptr) {
945 int64_t current_rss_pages = 0;
946 int matches = fscanf(statm,
"%*s%" Pd64 "", ¤t_rss_pages);
948 SaveErrorAndClose(statm);
952 return current_rss_pages * getpagesize();
958 int r = getrusage(RUSAGE_SELF, &
usage);
965static Mutex* signal_mutex =
nullptr;
966static SignalInfo* signal_handlers =
nullptr;
967static constexpr int kSignalsCount = 7;
968static const int kSignals[kSignalsCount] = {
969 SIGHUP, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGWINCH,
978 MutexLocker lock(signal_mutex);
979 const SignalInfo* handler = signal_handlers;
980 while (handler !=
nullptr) {
981 if (handler->signal() == signal) {
985 handler = handler->next();
991 for (
int i = 0;
i < kSignalsCount;
i++) {
992 if (kSignals[
i] == signal) {
1004 ThreadSignalBlocker blocker(kSignalsCount, kSignals);
1005 MutexLocker lock(signal_mutex);
1006 SignalInfo* handler = signal_handlers;
1009 while (handler !=
nullptr) {
1010 if (handler->signal() == signal) {
1011 oldact_handler = handler->oldact();
1015 handler = handler->next();
1018 struct sigaction act = {};
1020 sigemptyset(&act.sa_mask);
1021 for (
int i = 0;
i < kSignalsCount;
i++) {
1022 sigaddset(&act.sa_mask, kSignals[
i]);
1024 struct sigaction oldact = {};
1033 oldact_handler = oldact.sa_handler;
1036 new SignalInfo(fds[1], signal, oldact_handler, signal_handlers);
1041 ThreadSignalBlocker blocker(kSignalsCount, kSignals);
1042 MutexLocker lock(signal_mutex);
1043 SignalInfo* handler = signal_handlers;
1045 bool any_removed =
false;
1046 bool any_remaining =
false;
1047 while (handler !=
nullptr) {
1049 if (handler->signal() == signal) {
1051 if (signal_handlers == handler) {
1052 signal_handlers = handler->next();
1056 oldact_handler = handler->oldact();
1059 any_remaining =
true;
1062 SignalInfo*
next = handler->next();
1068 if (any_removed && !any_remaining) {
1069 struct sigaction act = {};
1070 act.sa_handler = oldact_handler;
1076 ThreadSignalBlocker blocker(kSignalsCount, kSignals);
1077 MutexLocker lock(signal_mutex);
1078 SignalInfo* handler = signal_handlers;
1080 bool any_remaining =
false;
1081 intptr_t signal = -1;
1082 while (handler !=
nullptr) {
1084 if (handler->fd() == fd) {
1086 if (signal_handlers == handler) {
1087 signal_handlers = handler->next();
1091 signal = handler->signal();
1093 any_remaining =
true;
1096 SignalInfo*
next = handler->next();
1102 if ((signal != -1) && !any_remaining) {
1103 struct sigaction act = {};
1104 act.sa_handler = oldact_handler;
1110 active_processes_ =
nullptr;
1111 ASSERT(ProcessInfoList::mutex_ ==
nullptr);
1112 ProcessInfoList::mutex_ =
new Mutex();
1116 ASSERT(ProcessInfoList::mutex_ !=
nullptr);
1117 delete ProcessInfoList::mutex_;
1118 ProcessInfoList::mutex_ =
nullptr;
1124 terminate_done_ =
false;
1125 ASSERT(ExitCodeHandler::monitor_ ==
nullptr);
1126 ExitCodeHandler::monitor_ =
new Monitor();
1130 ASSERT(ExitCodeHandler::monitor_ !=
nullptr);
1131 delete ExitCodeHandler::monitor_;
1132 ExitCodeHandler::monitor_ =
nullptr;
1139 ASSERT(signal_mutex ==
nullptr);
1140 signal_mutex =
new Mutex();
1141 signal_handlers =
nullptr;
1143 ASSERT(Process::global_exit_code_mutex_ ==
nullptr);
1144 Process::global_exit_code_mutex_ =
new Mutex();
1150 ASSERT(signal_mutex !=
nullptr);
1151 delete signal_mutex;
1152 signal_mutex =
nullptr;
1154 ASSERT(Process::global_exit_code_mutex_ !=
nullptr);
1155 delete Process::global_exit_code_mutex_;
1156 Process::global_exit_code_mutex_ =
nullptr;
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)
#define DEBUG_ASSERT(cond)
static char * StrError(int err, char *buffer, size_t bufsize)
static char * ScopedCString(intptr_t length)
static bool SetCurrent(Namespace *namespc, const char *path)
static intptr_t AvailableBytes(intptr_t fd)
static bool SetNonBlocking(intptr_t fd)
static void SaveErrorAndClose(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 IsDefault(Namespace *namespc)
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)