6#if defined(DART_HOST_OS_FUCHSIA)
12#include <fuchsia/io/cpp/fidl.h>
13#include <lib/fdio/directory.h>
14#include <lib/fdio/io.h>
15#include <lib/fdio/namespace.h>
16#include <lib/fdio/spawn.h>
24#include <zircon/process.h>
25#include <zircon/processargs.h>
26#include <zircon/status.h>
27#include <zircon/syscalls.h>
28#include <zircon/syscalls/object.h>
29#include <zircon/types.h>
43#if defined(PROCESS_LOGGING)
44#define LOG_ERR(msg, ...) Syslog::PrintErr("Dart Process: " msg, ##__VA_ARGS__)
45#define LOG_INFO(msg, ...) Syslog::Print("Dart Process: " msg, ##__VA_ARGS__)
47#define LOG_ERR(msg, ...)
48#define LOG_INFO(msg, ...)
54int Process::global_exit_code_ = 0;
55Mutex* Process::global_exit_code_mutex_ =
nullptr;
64 ProcessInfo(zx_handle_t
process, intptr_t fd)
65 : process_(
process), exit_pipe_fd_(fd) {}
69 LOG_ERR(
"Failed to close process exit code pipe");
71 zx_handle_close(process_);
73 zx_handle_t
process()
const {
return process_; }
74 intptr_t exit_pipe_fd()
const {
return exit_pipe_fd_; }
75 ProcessInfo*
next()
const {
return next_; }
76 void set_next(ProcessInfo*
info) { next_ =
info; }
80 intptr_t exit_pipe_fd_;
88class ProcessInfoList {
93 static void AddProcess(zx_handle_t
process, intptr_t fd) {
94 MutexLocker locker(mutex_);
96 info->set_next(active_processes_);
97 active_processes_ =
info;
100 static intptr_t LookupProcessExitFd(zx_handle_t
process) {
101 MutexLocker locker(mutex_);
102 ProcessInfo* current = active_processes_;
103 while (current !=
nullptr) {
104 if (current->process() ==
process) {
105 return current->exit_pipe_fd();
107 current = current->next();
112 static bool Exists(zx_handle_t
process) {
113 return LookupProcessExitFd(
process) != 0;
116 static void RemoveProcess(zx_handle_t
process) {
117 MutexLocker locker(mutex_);
118 ProcessInfo*
prev =
nullptr;
119 ProcessInfo* current = active_processes_;
120 while (current !=
nullptr) {
121 if (current->process() ==
process) {
122 if (
prev ==
nullptr) {
123 active_processes_ = current->next();
125 prev->set_next(current->next());
131 current = current->next();
138 static ProcessInfo* active_processes_;
141 static Mutex* mutex_;
147ProcessInfo* ProcessInfoList::active_processes_ =
nullptr;
148Mutex* ProcessInfoList::mutex_ =
nullptr;
154class ExitCodeHandler {
160 static void Start() {
163 MonitorLocker locker(monitor_);
167 LOG_INFO(
"ExitCodeHandler Starting\n");
169 zx_status_t status = zx_port_create(0, &port_);
170 if (status != ZX_OK) {
171 FATAL(
"ExitCodeHandler: zx_port_create failed: %s\n",
172 zx_status_get_string(status));
178 Thread::Start(
"dart:io Process.start", ExitCodeHandlerEntry, 0);
180 FATAL(
"Failed to start exit code handler worker thread %ld",
result);
186 static zx_status_t Add(zx_handle_t
process) {
187 MonitorLocker locker(monitor_);
189 return zx_object_wait_async(
process, port_,
static_cast<uint64_t
>(
process),
190 ZX_TASK_TERMINATED, ZX_WAIT_ASYNC_ONCE);
193 static void Terminate() {
194 MonitorLocker locker(monitor_);
200 LOG_INFO(
"ExitCodeHandler Terminating\n");
201 SendShutdownMessage();
203 while (!terminate_done_) {
206 zx_handle_close(port_);
207 LOG_INFO(
"ExitCodeHandler Terminated\n");
211 static constexpr uint64_t kShutdownPacketKey = 1;
213 static void SendShutdownMessage() {
214 zx_port_packet_t pkt;
215 pkt.key = kShutdownPacketKey;
216 zx_status_t status = zx_port_queue(port_, &pkt);
217 if (status != ZX_OK) {
219 zx_status_get_string(status));
225 static void ExitCodeHandlerEntry(
uword param) {
226 LOG_INFO(
"ExitCodeHandler Entering ExitCodeHandler thread\n");
228 zx_port_packet_t pkt;
230 zx_status_t status = zx_port_wait(port_, ZX_TIME_INFINITE, &pkt);
231 if (status != ZX_OK) {
232 FATAL(
"ExitCodeHandler: zx_port_wait failed: %s\n",
233 zx_status_get_string(status));
235 if (pkt.type == ZX_PKT_TYPE_USER) {
236 ASSERT(pkt.key == kShutdownPacketKey);
239 zx_handle_t
process =
static_cast<zx_handle_t
>(pkt.key);
240 zx_signals_t observed = pkt.signal.observed;
241 if ((observed & ZX_TASK_TERMINATED) == ZX_SIGNAL_NONE) {
242 LOG_ERR(
"ExitCodeHandler: Unexpected signals, process %u: %ux\n",
248 LOG_INFO(
"ExitCodeHandler thread shutting down\n");
249 terminate_done_ =
true;
253 static void SendProcessStatus(zx_handle_t
process) {
254 LOG_INFO(
"ExitCodeHandler thread getting process status: %u\n",
process);
255 int return_code = -1;
256 zx_info_process_t proc_info;
258 zx_object_get_info(
process, ZX_INFO_PROCESS, &proc_info,
259 sizeof(proc_info),
nullptr,
nullptr);
260 if (status != ZX_OK) {
262 zx_status_get_string(status));
264 return_code = proc_info.return_code;
267 LOG_INFO(
"ExitCodeHandler thread process %u exited with %d\n",
process,
270 const intptr_t exit_code_fd = ProcessInfoList::LookupProcessExitFd(
process);
271 LOG_INFO(
"ExitCodeHandler thread sending %u code %d on fd %ld\n",
process,
272 return_code, exit_code_fd);
273 if (exit_code_fd != 0) {
275 exit_message[0] =
abs(return_code);
276 exit_message[1] = return_code >= 0 ? 0 : 1;
278 sizeof(exit_message));
280 if ((
result == -1) && (errno != EPIPE)) {
285 LOG_INFO(
"ExitCodeHandler thread wrote %ld bytes to fd %ld\n",
result,
287 LOG_INFO(
"ExitCodeHandler thread removing process %u from list\n",
289 ProcessInfoList::RemoveProcess(
process);
291 LOG_ERR(
"ExitCodeHandler: Process %u not found\n",
process);
295 static zx_handle_t port_;
298 static bool terminate_done_;
299 static bool running_;
300 static Monitor* monitor_;
306zx_handle_t ExitCodeHandler::port_ = ZX_HANDLE_INVALID;
307bool ExitCodeHandler::running_ =
false;
308bool ExitCodeHandler::terminate_done_ =
false;
309Monitor* ExitCodeHandler::monitor_ =
nullptr;
312 ExitCodeHandler::Terminate();
316 return static_cast<intptr_t
>(getpid());
320 zx_info_task_stats_t task_stats;
321 zx_handle_t
process = zx_process_self();
323 zx_object_get_info(
process, ZX_INFO_TASK_STATS, &task_stats,
324 sizeof(task_stats),
nullptr,
nullptr);
325 if (status != ZX_OK) {
330 return task_stats.mem_private_bytes + task_stats.mem_shared_bytes;
341 explicit IOHandleScope(IOHandle* io_handle) : io_handle_(io_handle) {}
344 io_handle_->Release();
348 IOHandle* io_handle_;
360 IOHandle* out_iohandle =
reinterpret_cast<IOHandle*
>(
out);
361 IOHandle* err_iohandle =
reinterpret_cast<IOHandle*
>(err);
362 IOHandle* exit_iohandle =
reinterpret_cast<IOHandle*
>(exit_event);
376 zx_status_t status = zx_port_create(0, &
port);
377 if (status != ZX_OK) {
379 zx_status_get_string(status));
383 IOHandle* out_tmp = out_iohandle;
384 IOHandle* err_tmp = err_iohandle;
385 IOHandle* exit_tmp = exit_iohandle;
386 const uint64_t out_key =
reinterpret_cast<uint64_t
>(out_tmp);
387 const uint64_t err_key =
reinterpret_cast<uint64_t
>(err_tmp);
388 const uint64_t exit_key =
reinterpret_cast<uint64_t
>(exit_tmp);
389 const uint32_t events = POLLRDHUP | POLLIN;
390 if (!out_tmp->AsyncWait(
port, events, out_key)) {
393 if (!err_tmp->AsyncWait(
port, events, err_key)) {
396 if (!exit_tmp->AsyncWait(
port, events, exit_key)) {
399 while ((out_tmp !=
nullptr) || (err_tmp !=
nullptr) ||
400 (exit_tmp !=
nullptr)) {
401 zx_port_packet_t pkt;
402 status = zx_port_wait(
port, ZX_TIME_INFINITE, &pkt);
403 if (status != ZX_OK) {
405 zx_status_get_string(status));
408 IOHandle* event_handle =
reinterpret_cast<IOHandle*
>(pkt.key);
409 const intptr_t event_mask = event_handle->WaitEnd(pkt.signal.observed);
410 if (event_handle == out_tmp) {
411 if ((event_mask & POLLIN) != 0) {
413 if (!out_data.Read(out_tmp->fd(), avail)) {
417 if ((event_mask & POLLRDHUP) != 0) {
418 out_tmp->CancelWait(
port, out_key);
421 }
else if (event_handle == err_tmp) {
422 if ((event_mask & POLLIN) != 0) {
424 if (!err_data.Read(err_tmp->fd(), avail)) {
428 if ((event_mask & POLLRDHUP) != 0) {
429 err_tmp->CancelWait(
port, err_key);
432 }
else if (event_handle == exit_tmp) {
433 if ((event_mask & POLLIN) != 0) {
443 if ((event_mask & POLLRDHUP) != 0) {
444 exit_tmp->CancelWait(
port, exit_key);
451 if (out_tmp !=
nullptr) {
452 if (!out_tmp->AsyncWait(
port, events, out_key)) {
456 if (err_tmp !=
nullptr) {
457 if (!err_tmp->AsyncWait(
port, events, err_key)) {
461 if (exit_tmp !=
nullptr) {
462 if (!exit_tmp->AsyncWait(
port, events, exit_key)) {
469 result->set_stdout_data(out_data.GetData());
470 result->set_stderr_data(err_data.GetData());
475 intptr_t exit_code = exit_code_data.ints[0];
476 intptr_t negative = exit_code_data.ints[1];
478 exit_code = -exit_code;
480 result->set_exit_code(exit_code);
483 zx_handle_t
process =
static_cast<zx_handle_t
>(pid);
489 LOG_INFO(
"Sending signal %d to process with id %ld\n", signal,
id);
491 if ((signal != SIGTERM) && (signal != SIGKILL)) {
492 LOG_ERR(
"Signal %d not supported\n", signal);
498 zx_handle_t
process =
static_cast<zx_handle_t
>(
id);
499 if (!ProcessInfoList::Exists(
process)) {
500 LOG_ERR(
"Process %ld wasn't in the ProcessInfoList\n",
id);
504 zx_status_t status = zx_task_kill(
process);
505 if (status != ZX_OK) {
506 LOG_ERR(
"zx_task_kill failed: %s\n", zx_status_get_string(status));
510 LOG_INFO(
"Signal %d sent successfully to process %ld\n", signal,
id);
514class ProcessStarter {
516 ProcessStarter(Namespace* namespc,
519 intptr_t arguments_length,
520 const char* working_directory,
522 intptr_t environment_length,
528 intptr_t* exit_event,
529 char** os_error_message)
532 working_directory_(working_directory),
538 exit_event_(exit_event),
539 os_error_message_(os_error_message) {
540 LOG_INFO(
"ProcessStarter: ctor %s with %ld args, mode = %d\n",
path,
541 arguments_length,
mode);
548 (arguments_length + 2) *
sizeof(*program_arguments_)));
549 program_arguments_[0] =
const_cast<char*
>(path_);
550 for (
int i = 0;
i < arguments_length;
i++) {
551 program_arguments_[
i + 1] = arguments[
i];
553 program_arguments_[arguments_length + 1] =
nullptr;
555 program_environment_ =
nullptr;
558 (environment_length + 1) *
sizeof(*program_environment_)));
559 for (
int i = 0;
i < environment_length;
i++) {
562 program_environment_[environment_length] =
nullptr;
567 if (read_in_ != -1) {
570 if (read_err_ != -1) {
573 if (write_out_ != -1) {
579 LOG_INFO(
"ProcessStarter: Start()\n");
580 int exit_pipe_fds[2];
584 "Failed to create exit code pipe for process start.");
587 LOG_INFO(
"ProcessStarter: Start() set up exit_pipe_fds (%d, %d)\n",
588 exit_pipe_fds[0], exit_pipe_fds[1]);
590 NamespaceScope ns(namespc_, path_);
593 if (ns.fd() == AT_FDCWD) {
594 status = fdio_open_fd(
596 static_cast<uint32_t
>(fuchsia::io::OpenFlags::RIGHT_READABLE |
597 fuchsia::io::OpenFlags::RIGHT_EXECUTABLE),
600 status = fdio_open_fd_at(
602 static_cast<uint32_t
>(fuchsia::io::OpenFlags::RIGHT_READABLE |
603 fuchsia::io::OpenFlags::RIGHT_EXECUTABLE),
606 if (status != ZX_OK) {
607 close(exit_pipe_fds[0]);
608 close(exit_pipe_fds[1]);
610 "Failed to load executable for process start (fdio_open_fd_at %s).",
611 zx_status_get_string(status));
614 zx_handle_t vmo = ZX_HANDLE_INVALID;
615 status = fdio_get_vmo_exec(pathfd, &vmo);
617 if (status != ZX_OK) {
618 close(exit_pipe_fds[0]);
619 close(exit_pipe_fds[1]);
621 "Failed to load executable for process start (fdio_get_vmo_exec %s).",
622 zx_status_get_string(status));
626 fdio_spawn_action_t* actions;
627 const intptr_t actions_count =
628 BuildSpawnActions(namespc_->namespc()->fdio_ns(), &actions);
629 if (actions_count < 0) {
630 zx_handle_close(vmo);
631 close(exit_pipe_fds[0]);
632 close(exit_pipe_fds[1]);
641 LOG_INFO(
"ProcessStarter: Start() Calling fdio_spawn_vmo\n");
642 zx_handle_t
process = ZX_HANDLE_INVALID;
643 char err_msg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];
644 uint32_t
flags = FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_DEFAULT_LDSVC |
645 FDIO_SPAWN_CLONE_UTC_CLOCK;
646 status = fdio_spawn_vmo(ZX_HANDLE_INVALID,
flags, vmo, program_arguments_,
647 program_environment_, actions_count, actions,
651 if (status != ZX_OK) {
652 LOG_ERR(
"ProcessStarter: Start() fdio_spawn_vmo failed\n");
653 close(exit_pipe_fds[0]);
654 close(exit_pipe_fds[1]);
655 ReportStartError(
"Process start failed: %s\n", err_msg);
659 LOG_INFO(
"ProcessStarter: Start() adding %u to list with exit_pipe %d\n",
661 ProcessInfoList::AddProcess(
process, exit_pipe_fds[1]);
662 ExitCodeHandler::Start();
663 status = ExitCodeHandler::Add(
process);
664 if (status != ZX_OK) {
665 LOG_ERR(
"ProcessStarter: ExitCodeHandler: Add failed: %s\n",
666 zx_status_get_string(status));
667 close(exit_pipe_fds[0]);
668 close(exit_pipe_fds[1]);
670 ProcessInfoList::RemoveProcess(
process);
671 ReportStartError(
"Process start failed: %s\n",
672 zx_status_get_string(status));
682 *in_ =
reinterpret_cast<intptr_t
>(
new IOHandle(read_in_));
685 *err_ =
reinterpret_cast<intptr_t
>(
new IOHandle(read_err_));
688 *out_ =
reinterpret_cast<intptr_t
>(
new IOHandle(write_out_));
691 *exit_event_ =
reinterpret_cast<intptr_t
>(
new IOHandle(exit_pipe_fds[0]));
697 const intptr_t kMaxMessageSize = 256;
706 zx_status_t AddPipe(
int target_fd,
708 fdio_spawn_action_t*
action) {
709 zx_status_t status = fdio_pipe_half(local_fd, &
action->h.handle);
710 if (status != ZX_OK)
return status;
711 action->action = FDIO_SPAWN_ACTION_ADD_HANDLE;
712 action->h.id = PA_HND(PA_HND_TYPE(PA_FD), target_fd);
717 intptr_t BuildSpawnActions(fdio_ns_t* ns, fdio_spawn_action_t** actions_out) {
718 const intptr_t fixed_actions_cnt = 4;
723 fdio_flat_namespace_t* flat_ns =
nullptr;
725 status = fdio_ns_export(ns, &flat_ns);
726 if (status != ZX_OK) {
727 LOG_ERR(
"ProcessStarter: BuildSpawnActions: fdio_ns_export: %s\n",
728 zx_status_get_string(status));
731 ns_cnt = flat_ns->count;
735 const intptr_t actions_cnt = ns_cnt + fixed_actions_cnt;
736 fdio_spawn_action_t* actions =
new fdio_spawn_action_t[actions_cnt];
740 status = AddPipe(0, &write_out_, &actions[0]);
741 if (status != ZX_OK) {
742 LOG_ERR(
"ProcessStarter: BuildSpawnActions: stdout AddPipe failed: %s\n",
743 zx_status_get_string(status));
744 if (flat_ns !=
nullptr) {
745 fdio_ns_free_flat_ns(flat_ns);
749 status = AddPipe(1, &read_in_, &actions[1]);
750 if (status != ZX_OK) {
751 LOG_ERR(
"ProcessStarter: BuildSpawnActions: stdin AddPipe failed: %s\n",
752 zx_status_get_string(status));
753 if (flat_ns !=
nullptr) {
754 fdio_ns_free_flat_ns(flat_ns);
758 status = AddPipe(2, &read_err_, &actions[2]);
759 if (status != ZX_OK) {
760 LOG_ERR(
"ProcessStarter: BuildSpawnActions: stderr AddPipe failed: %s\n",
761 zx_status_get_string(status));
762 if (flat_ns !=
nullptr) {
763 fdio_ns_free_flat_ns(flat_ns);
769 .action = FDIO_SPAWN_ACTION_SET_NAME,
771 .data = program_arguments_[0],
778 for (
size_t i = 0;
i < flat_ns->count;
i++) {
780 actions[fixed_actions_cnt +
i] = {
781 .action = FDIO_SPAWN_ACTION_ADD_NS_ENTRY,
784 .handle = flat_ns->handle[
i],
788 flat_ns->handle[
i] = ZX_HANDLE_INVALID;
790 fdio_ns_free_flat_ns(flat_ns);
794 *actions_out = actions;
802 char** program_arguments_;
803 char** program_environment_;
807 const char* working_directory_;
813 intptr_t* exit_event_;
814 char** os_error_message_;
823 intptr_t arguments_length,
824 const char* working_directory,
826 intptr_t environment_length,
832 intptr_t* exit_event,
833 char** os_error_message) {
836 "Only ProcessStartMode.NORMAL is supported on this platform");
839 ProcessStarter starter(namespc,
path, arguments, arguments_length,
840 working_directory,
environment, environment_length,
841 mode, in,
out, err,
id, exit_event, os_error_message);
842 return starter.Start();
855 active_processes_ =
nullptr;
856 ASSERT(ProcessInfoList::mutex_ ==
nullptr);
857 ProcessInfoList::mutex_ =
new Mutex();
861 ASSERT(ProcessInfoList::mutex_ !=
nullptr);
862 delete ProcessInfoList::mutex_;
863 ProcessInfoList::mutex_ =
nullptr;
867 port_ = ZX_HANDLE_INVALID;
869 terminate_done_ =
false;
870 ASSERT(ExitCodeHandler::monitor_ ==
nullptr);
871 ExitCodeHandler::monitor_ =
new Monitor();
875 ASSERT(ExitCodeHandler::monitor_ !=
nullptr);
876 delete ExitCodeHandler::monitor_;
877 ExitCodeHandler::monitor_ =
nullptr;
884 ASSERT(Process::global_exit_code_mutex_ ==
nullptr);
885 Process::global_exit_code_mutex_ =
new Mutex();
889 ASSERT(Process::global_exit_code_mutex_ !=
nullptr);
890 delete Process::global_exit_code_mutex_;
891 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 void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static char * ScopedCopyCString(const char *str)
static char * ScopedCString(intptr_t length)
static intptr_t AvailableBytes(intptr_t fd)
static bool SetNonBlocking(intptr_t fd)
static ssize_t WriteToBlocking(int fd, const void *buffer, size_t count)
static constexpr int64_t kNoTimeout
static void ClearSignalHandler(intptr_t signal, Dart_Port port)
static void ClearSignalHandlerByFd(intptr_t fd, Dart_Port port)
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 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)
FlutterSemanticsFlag flags
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
uint32_t uint32_t * format
PRINTF_ATTRIBUTE(1, 2) static void PrintErrAndExit(const char *format
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
SIN Vec< N, float > abs(const Vec< N, float > &x)
#define NO_RETRY_EXPECTED(expression)
static void process(const char *inPath, const char *lexer, const char *token, const char *hPath, const char *cppPath)