1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "platform/globals.h"
6#if defined(HOST_OS_ANDROID)
7
8#include "bin/process.h"
9
10#include <errno.h> // NOLINT
11#include <fcntl.h> // NOLINT
12#include <poll.h> // NOLINT
13#include <stdio.h> // NOLINT
14#include <stdlib.h> // NOLINT
15#include <string.h> // NOLINT
16#include <sys/wait.h> // NOLINT
17#include <unistd.h> // NOLINT
18
19#include "bin/dartutils.h"
20#include "bin/directory.h"
21#include "bin/fdutils.h"
22#include "bin/file.h"
23#include "bin/lockers.h"
24#include "bin/namespace.h"
25#include "bin/reference_counting.h"
26#include "bin/thread.h"
27#include "platform/syslog.h"
28
29#include "platform/signal_blocker.h"
30#include "platform/utils.h"
31
32extern char** environ;
33
34namespace dart {
35namespace bin {
36
37int Process::global_exit_code_ = 0;
38Mutex* Process::global_exit_code_mutex_ = nullptr;
39Process::ExitHook Process::exit_hook_ = NULL;
40
41// ProcessInfo is used to map a process id to the file descriptor for
42// the pipe used to communicate the exit code of the process to Dart.
43// ProcessInfo objects are kept in the static singly-linked
44// ProcessInfoList.
45class ProcessInfo {
46 public:
47 ProcessInfo(pid_t pid, intptr_t fd) : pid_(pid), fd_(fd) {}
48 ~ProcessInfo() {
49 int closed = close(fd_);
50 if (closed != 0) {
51 FATAL("Failed to close process exit code pipe");
52 }
53 }
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; }
58
59 private:
60 pid_t pid_;
61 intptr_t fd_;
62 ProcessInfo* next_;
63
64 DISALLOW_COPY_AND_ASSIGN(ProcessInfo);
65};
66
67// Singly-linked list of ProcessInfo objects for all active processes
68// started from Dart.
69class ProcessInfoList {
70 public:
71 static void Init();
72 static void Cleanup();
73
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;
79 }
80
81 static intptr_t LookupProcessExitFd(pid_t pid) {
82 MutexLocker locker(mutex_);
83 ProcessInfo* current = active_processes_;
84 while (current != NULL) {
85 if (current->pid() == pid) {
86 return current->fd();
87 }
88 current = current->next();
89 }
90 return 0;
91 }
92
93 static void RemoveProcess(pid_t pid) {
94 MutexLocker locker(mutex_);
95 ProcessInfo* prev = NULL;
96 ProcessInfo* current = active_processes_;
97 while (current != NULL) {
98 if (current->pid() == pid) {
99 if (prev == NULL) {
100 active_processes_ = current->next();
101 } else {
102 prev->set_next(current->next());
103 }
104 delete current;
105 return;
106 }
107 prev = current;
108 current = current->next();
109 }
110 }
111
112 private:
113 // Linked list of ProcessInfo objects for all active processes
114 // started from Dart code.
115 static ProcessInfo* active_processes_;
116 // Mutex protecting all accesses to the linked list of active
117 // processes.
118 static Mutex* mutex_;
119
120 DISALLOW_ALLOCATION();
121 DISALLOW_IMPLICIT_CONSTRUCTORS(ProcessInfoList);
122};
123
124ProcessInfo* ProcessInfoList::active_processes_ = NULL;
125Mutex* ProcessInfoList::mutex_ = nullptr;
126
127// The exit code handler sets up a separate thread which waits for child
128// processes to terminate. That separate thread can then get the exit code from
129// processes that have exited and communicate it to Dart through the
130// event loop.
131class ExitCodeHandler {
132 public:
133 static void Init();
134 static void Cleanup();
135
136 // Notify the ExitCodeHandler that another process exists.
137 static void ProcessStarted() {
138 // Multiple isolates could be starting processes at the same
139 // time. Make sure that only one ExitCodeHandler thread exists.
140 MonitorLocker locker(monitor_);
141 process_count_++;
142
143 monitor_->Notify();
144
145 if (running_) {
146 return;
147 }
148
149 // Start thread that handles process exits when wait returns.
150 int result =
151 Thread::Start("dart:io Process.start", ExitCodeHandlerEntry, 0);
152 if (result != 0) {
153 FATAL1("Failed to start exit code handler worker thread %d", result);
154 }
155
156 running_ = true;
157 }
158
159 static void TerminateExitCodeThread() {
160 MonitorLocker locker(monitor_);
161
162 if (!running_) {
163 return;
164 }
165
166 // Set terminate_done_ to false, so we can use it as a guard for our
167 // monitor.
168 running_ = false;
169
170 // Wake up the [ExitCodeHandler] thread which is blocked on `wait()` (see
171 // [ExitCodeHandlerEntry]).
172 if (TEMP_FAILURE_RETRY(fork()) == 0) {
173 // We avoid running through registered atexit() handlers because that is
174 // unnecessary work.
175 _exit(0);
176 }
177
178 monitor_->Notify();
179
180 while (!terminate_done_) {
181 monitor_->Wait(Monitor::kNoTimeout);
182 }
183 }
184
185 private:
186 // Entry point for the separate exit code handler thread started by
187 // the ExitCodeHandler.
188 static void ExitCodeHandlerEntry(uword param) {
189 pid_t pid = 0;
190 int status = 0;
191 while (true) {
192 {
193 MonitorLocker locker(monitor_);
194 while (running_ && (process_count_ == 0)) {
195 monitor_->Wait(Monitor::kNoTimeout);
196 }
197 if (!running_) {
198 terminate_done_ = true;
199 monitor_->Notify();
200 return;
201 }
202 }
203
204 if ((pid = TEMP_FAILURE_RETRY(wait(&status))) > 0) {
205 int exit_code = 0;
206 int negative = 0;
207 if (WIFEXITED(status)) {
208 exit_code = WEXITSTATUS(status);
209 }
210 if (WIFSIGNALED(status)) {
211 exit_code = WTERMSIG(status);
212 negative = 1;
213 }
214 intptr_t exit_code_fd = ProcessInfoList::LookupProcessExitFd(pid);
215 if (exit_code_fd != 0) {
216 int message[2] = {exit_code, negative};
217 ssize_t result =
218 FDUtils::WriteToBlocking(exit_code_fd, &message, sizeof(message));
219 // If the process has been closed, the read end of the exit
220 // pipe has been closed. It is therefore not a problem that
221 // write fails with a broken pipe error. Other errors should
222 // not happen.
223 if ((result != -1) && (result != sizeof(message))) {
224 FATAL("Failed to write entire process exit message");
225 } else if ((result == -1) && (errno != EPIPE)) {
226 FATAL1("Failed to write exit code: %d", errno);
227 }
228 ProcessInfoList::RemoveProcess(pid);
229 {
230 MonitorLocker locker(monitor_);
231 process_count_--;
232 }
233 }
234 } else if (pid < 0) {
235 FATAL1("Wait for process exit failed: %d", errno);
236 }
237 }
238 }
239
240 static bool terminate_done_;
241 static int process_count_;
242 static bool running_;
243 static Monitor* monitor_;
244
245 DISALLOW_ALLOCATION();
246 DISALLOW_IMPLICIT_CONSTRUCTORS(ExitCodeHandler);
247};
248
249bool ExitCodeHandler::running_ = false;
250int ExitCodeHandler::process_count_ = 0;
251bool ExitCodeHandler::terminate_done_ = false;
252Monitor* ExitCodeHandler::monitor_ = nullptr;
253
254class ProcessStarter {
255 public:
256 ProcessStarter(Namespace* namespc,
257 const char* path,
258 char* arguments[],
259 intptr_t arguments_length,
260 const char* working_directory,
261 char* environment[],
262 intptr_t environment_length,
263 ProcessStartMode mode,
264 intptr_t* in,
265 intptr_t* out,
266 intptr_t* err,
267 intptr_t* id,
268 intptr_t* exit_event,
269 char** os_error_message)
270 : namespc_(namespc),
271 path_(path),
272 working_directory_(working_directory),
273 mode_(mode),
274 in_(in),
275 out_(out),
276 err_(err),
277 id_(id),
278 exit_event_(exit_event),
279 os_error_message_(os_error_message) {
280 read_in_[0] = -1;
281 read_in_[1] = -1;
282 read_err_[0] = -1;
283 read_err_[1] = -1;
284 write_out_[0] = -1;
285 write_out_[1] = -1;
286 exec_control_[0] = -1;
287 exec_control_[1] = -1;
288
289 program_arguments_ = reinterpret_cast<char**>(Dart_ScopeAllocate(
290 (arguments_length + 2) * sizeof(*program_arguments_)));
291 program_arguments_[0] = const_cast<char*>(path_);
292 for (int i = 0; i < arguments_length; i++) {
293 program_arguments_[i + 1] = arguments[i];
294 }
295 program_arguments_[arguments_length + 1] = NULL;
296
297 program_environment_ = NULL;
298 if (environment != NULL) {
299 program_environment_ = reinterpret_cast<char**>(Dart_ScopeAllocate(
300 (environment_length + 1) * sizeof(*program_environment_)));
301 for (int i = 0; i < environment_length; i++) {
302 program_environment_[i] = environment[i];
303 }
304 program_environment_[environment_length] = NULL;
305 }
306 }
307
308 int Start() {
309 // Create pipes required.
310 int err = CreatePipes();
311 if (err != 0) {
312 return err;
313 }
314
315 // Fork to create the new process.
316 pid_t pid = TEMP_FAILURE_RETRY(fork());
317 if (pid < 0) {
318 // Failed to fork.
319 return CleanupAndReturnError();
320 } else if (pid == 0) {
321 // This runs in the new process.
322 NewProcess();
323 }
324
325 // This runs in the original process.
326
327 // If the child process is not started in detached mode, be sure to
328 // listen for exit-codes, now that we have a non detached child process
329 // and also Register this child process.
330 if (Process::ModeIsAttached(mode_)) {
331 ExitCodeHandler::ProcessStarted();
332 err = RegisterProcess(pid);
333 if (err != 0) {
334 return err;
335 }
336 }
337
338 // Notify child process to start. This is done to delay the call to exec
339 // until the process is registered above, and we are ready to receive the
340 // exit code.
341 char msg = '1';
342 int bytes_written =
343 FDUtils::WriteToBlocking(read_in_[1], &msg, sizeof(msg));
344 if (bytes_written != sizeof(msg)) {
345 return CleanupAndReturnError();
346 }
347
348 // Read the result of executing the child process.
349 close(exec_control_[1]);
350 exec_control_[1] = -1;
351 if (Process::ModeIsAttached(mode_)) {
352 err = ReadExecResult();
353 } else {
354 err = ReadDetachedExecResult(&pid);
355 }
356 close(exec_control_[0]);
357 exec_control_[0] = -1;
358
359 // Return error code if any failures.
360 if (err != 0) {
361 if (Process::ModeIsAttached(mode_)) {
362 // Since exec() failed, we're not interested in the exit code.
363 // We close the reading side of the exit code pipe here.
364 // GetProcessExitCodes will get a broken pipe error when it
365 // tries to write to the writing side of the pipe and it will
366 // ignore the error.
367 close(*exit_event_);
368 *exit_event_ = -1;
369 }
370 CloseAllPipes();
371 return err;
372 }
373
374 if (Process::ModeHasStdio(mode_)) {
375 // Connect stdio, stdout and stderr.
376 FDUtils::SetNonBlocking(read_in_[0]);
377 *in_ = read_in_[0];
378 close(read_in_[1]);
379 FDUtils::SetNonBlocking(write_out_[1]);
380 *out_ = write_out_[1];
381 close(write_out_[0]);
382 FDUtils::SetNonBlocking(read_err_[0]);
383 *err_ = read_err_[0];
384 close(read_err_[1]);
385 } else {
386 // Close all fds.
387 close(read_in_[0]);
388 close(read_in_[1]);
389 ASSERT(write_out_[0] == -1);
390 ASSERT(write_out_[1] == -1);
391 ASSERT(read_err_[0] == -1);
392 ASSERT(read_err_[1] == -1);
393 }
394 ASSERT(exec_control_[0] == -1);
395 ASSERT(exec_control_[1] == -1);
396
397 *id_ = pid;
398 return 0;
399 }
400
401 private:
402 int CreatePipes() {
403 int result;
404 result = TEMP_FAILURE_RETRY(pipe2(exec_control_, O_CLOEXEC));
405 if (result < 0) {
406 return CleanupAndReturnError();
407 }
408
409 // For a detached process the pipe to connect stdout is still used for
410 // signaling when to do the first fork.
411 result = TEMP_FAILURE_RETRY(pipe2(read_in_, O_CLOEXEC));
412 if (result < 0) {
413 return CleanupAndReturnError();
414 }
415
416 // For detached processes the pipe to connect stderr and stdin are not used.
417 if (Process::ModeHasStdio(mode_)) {
418 result = TEMP_FAILURE_RETRY(pipe2(read_err_, O_CLOEXEC));
419 if (result < 0) {
420 return CleanupAndReturnError();
421 }
422
423 result = TEMP_FAILURE_RETRY(pipe2(write_out_, O_CLOEXEC));
424 if (result < 0) {
425 return CleanupAndReturnError();
426 }
427 }
428
429 return 0;
430 }
431
432 void NewProcess() {
433 // Wait for parent process before setting up the child process.
434 char msg;
435 int bytes_read = FDUtils::ReadFromBlocking(read_in_[0], &msg, sizeof(msg));
436 if (bytes_read != sizeof(msg)) {
437 perror("Failed receiving notification message");
438 exit(1);
439 }
440 if (Process::ModeIsAttached(mode_)) {
441 ExecProcess();
442 } else {
443 ExecDetachedProcess();
444 }
445 }
446
447 // Tries to find path_ relative to the current namespace unless it should be
448 // searched in the PATH.
449 // The path that should be passed to exec is returned in realpath.
450 // Returns true on success, and false if there was an error that should
451 // be reported to the parent.
452 bool FindPathInNamespace(char* realpath, intptr_t realpath_size) {
453 // Perform a PATH search if there's no slash in the path.
454 if (strchr(path_, '/') == NULL) {
455 // TODO(zra): If there is a non-default namespace, the entries in PATH
456 // should be treated as relative to the namespace.
457 strncpy(realpath, path_, realpath_size);
458 realpath[realpath_size - 1] = '\0';
459 return true;
460 }
461 NamespaceScope ns(namespc_, path_);
462 const int fd =
463 TEMP_FAILURE_RETRY(openat(ns.fd(), ns.path(), O_RDONLY | O_CLOEXEC));
464 if (fd == -1) {
465 return false;
466 }
467 char procpath[PATH_MAX];
468 snprintf(procpath, PATH_MAX, "/proc/self/fd/%d", fd);
469 const intptr_t length =
470 TEMP_FAILURE_RETRY(readlink(procpath, realpath, realpath_size));
471 if (length < 0) {
472 FDUtils::SaveErrorAndClose(fd);
473 return false;
474 }
475 realpath[length] = '\0';
476 FDUtils::SaveErrorAndClose(fd);
477 return true;
478 }
479
480 void ExecProcess() {
481 if (mode_ == kNormal) {
482 if (TEMP_FAILURE_RETRY(dup2(write_out_[0], STDIN_FILENO)) == -1) {
483 ReportChildError();
484 }
485
486 if (TEMP_FAILURE_RETRY(dup2(read_in_[1], STDOUT_FILENO)) == -1) {
487 ReportChildError();
488 }
489
490 if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) {
491 ReportChildError();
492 }
493 } else {
494 ASSERT(mode_ == kInheritStdio);
495 }
496
497 if (working_directory_ != NULL &&
498 !Directory::SetCurrent(namespc_, working_directory_)) {
499 ReportChildError();
500 }
501
502 if (program_environment_ != NULL) {
503 environ = program_environment_;
504 }
505
506 char realpath[PATH_MAX];
507 if (!FindPathInNamespace(realpath, PATH_MAX)) {
508 ReportChildError();
509 }
510 // TODO(dart:io) Test for the existence of execveat, and use it instead.
511 execvp(realpath, const_cast<char* const*>(program_arguments_));
512 ReportChildError();
513 }
514
515 void ExecDetachedProcess() {
516 if (mode_ == kDetached) {
517 ASSERT(write_out_[0] == -1);
518 ASSERT(write_out_[1] == -1);
519 ASSERT(read_err_[0] == -1);
520 ASSERT(read_err_[1] == -1);
521 // For a detached process the pipe to connect stdout is only used for
522 // signaling when to do the first fork.
523 close(read_in_[0]);
524 read_in_[0] = -1;
525 close(read_in_[1]);
526 read_in_[1] = -1;
527 } else {
528 // Don't close any fds if keeping stdio open to the detached process.
529 ASSERT(mode_ == kDetachedWithStdio);
530 }
531 // Fork once more to start a new session.
532 pid_t pid = TEMP_FAILURE_RETRY(fork());
533 if (pid < 0) {
534 ReportChildError();
535 } else if (pid == 0) {
536 // Start a new session.
537 if (TEMP_FAILURE_RETRY(setsid()) == -1) {
538 ReportChildError();
539 } else {
540 // Do a final fork to not be the session leader.
541 pid = TEMP_FAILURE_RETRY(fork());
542 if (pid < 0) {
543 ReportChildError();
544 } else if (pid == 0) {
545 if (mode_ == kDetached) {
546 SetupDetached();
547 } else {
548 SetupDetachedWithStdio();
549 }
550
551 if ((working_directory_ != NULL) &&
552 !Directory::SetCurrent(namespc_, working_directory_)) {
553 ReportChildError();
554 }
555
556 if (program_environment_ != NULL) {
557 environ = program_environment_;
558 }
559
560 // Report the final PID and do the exec.
561 ReportPid(getpid()); // getpid cannot fail.
562 char realpath[PATH_MAX];
563 if (!FindPathInNamespace(realpath, PATH_MAX)) {
564 ReportChildError();
565 }
566 // TODO(dart:io) Test for the existence of execveat, and use it
567 // instead.
568 execvp(realpath, const_cast<char* const*>(program_arguments_));
569 ReportChildError();
570 } else {
571 // Exit the intermediate process.
572 exit(0);
573 }
574 }
575 } else {
576 // Exit the intermediate process.
577 exit(0);
578 }
579 }
580
581 int RegisterProcess(pid_t pid) {
582 int result;
583 int event_fds[2];
584 result = TEMP_FAILURE_RETRY(pipe2(event_fds, O_CLOEXEC));
585 if (result < 0) {
586 return CleanupAndReturnError();
587 }
588
589 ProcessInfoList::AddProcess(pid, event_fds[1]);
590 *exit_event_ = event_fds[0];
591 FDUtils::SetNonBlocking(event_fds[0]);
592 return 0;
593 }
594
595 int ReadExecResult() {
596 int child_errno;
597 int bytes_read = -1;
598 // Read exec result from child. If no data is returned the exec was
599 // successful and the exec call closed the pipe. Otherwise the errno
600 // is written to the pipe.
601 bytes_read = FDUtils::ReadFromBlocking(exec_control_[0], &child_errno,
602 sizeof(child_errno));
603 if (bytes_read == sizeof(child_errno)) {
604 ReadChildError();
605 return child_errno;
606 } else if (bytes_read == -1) {
607 return errno;
608 }
609 return 0;
610 }
611
612 int ReadDetachedExecResult(pid_t* pid) {
613 int child_errno;
614 int bytes_read = -1;
615 // Read exec result from child. If only pid data is returned the exec was
616 // successful and the exec call closed the pipe. Otherwise the errno
617 // is written to the pipe as well.
618 int result[2];
619 bytes_read =
620 FDUtils::ReadFromBlocking(exec_control_[0], result, sizeof(result));
621 if (bytes_read == sizeof(int)) {
622 *pid = result[0];
623 } else if (bytes_read == 2 * sizeof(int)) {
624 *pid = result[0];
625 child_errno = result[1];
626 ReadChildError();
627 return child_errno;
628 } else if (bytes_read == -1) {
629 return errno;
630 }
631 return 0;
632 }
633
634 void SetupDetached() {
635 ASSERT(mode_ == kDetached);
636
637 // Close all open file descriptors except for exec_control_[1].
638 int max_fds = sysconf(_SC_OPEN_MAX);
639 if (max_fds == -1) {
640 max_fds = _POSIX_OPEN_MAX;
641 }
642 for (int fd = 0; fd < max_fds; fd++) {
643 if (fd != exec_control_[1]) {
644 close(fd);
645 }
646 }
647
648 // Re-open stdin, stdout and stderr and connect them to /dev/null.
649 // The loop above should already have closed all of them, so
650 // creating new file descriptors should start at STDIN_FILENO.
651 int fd = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
652 if (fd != STDIN_FILENO) {
653 ReportChildError();
654 }
655 if (TEMP_FAILURE_RETRY(dup2(STDIN_FILENO, STDOUT_FILENO)) !=
656 STDOUT_FILENO) {
657 ReportChildError();
658 }
659 if (TEMP_FAILURE_RETRY(dup2(STDIN_FILENO, STDERR_FILENO)) !=
660 STDERR_FILENO) {
661 ReportChildError();
662 }
663 }
664
665 void SetupDetachedWithStdio() {
666 // Close all open file descriptors except for
667 // exec_control_[1], write_out_[0], read_in_[1] and
668 // read_err_[1].
669 int max_fds = sysconf(_SC_OPEN_MAX);
670 if (max_fds == -1) {
671 max_fds = _POSIX_OPEN_MAX;
672 }
673 for (int fd = 0; fd < max_fds; fd++) {
674 if ((fd != exec_control_[1]) && (fd != write_out_[0]) &&
675 (fd != read_in_[1]) && (fd != read_err_[1])) {
676 close(fd);
677 }
678 }
679
680 if (TEMP_FAILURE_RETRY(dup2(write_out_[0], STDIN_FILENO)) == -1) {
681 ReportChildError();
682 }
683 close(write_out_[0]);
684
685 if (TEMP_FAILURE_RETRY(dup2(read_in_[1], STDOUT_FILENO)) == -1) {
686 ReportChildError();
687 }
688 close(read_in_[1]);
689
690 if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) {
691 ReportChildError();
692 }
693 close(read_err_[1]);
694 }
695
696 int CleanupAndReturnError() {
697 int actual_errno = errno;
698 // If CleanupAndReturnError is called without an actual errno make
699 // sure to return an error anyway.
700 if (actual_errno == 0) {
701 actual_errno = EPERM;
702 }
703 SetChildOsErrorMessage();
704 CloseAllPipes();
705 return actual_errno;
706 }
707
708 void SetChildOsErrorMessage() {
709 const int kBufferSize = 1024;
710 char* error_message = DartUtils::ScopedCString(kBufferSize);
711 Utils::StrError(errno, error_message, kBufferSize);
712 *os_error_message_ = error_message;
713 }
714
715 void ReportChildError() {
716 // In the case of failure in the child process write the errno and
717 // the OS error message to the exec control pipe and exit.
718 int child_errno = errno;
719 const int kBufferSize = 1024;
720 char error_buf[kBufferSize];
721 char* os_error_message = Utils::StrError(errno, error_buf, kBufferSize);
722 int bytes_written = FDUtils::WriteToBlocking(exec_control_[1], &child_errno,
723 sizeof(child_errno));
724 if (bytes_written == sizeof(child_errno)) {
725 FDUtils::WriteToBlocking(exec_control_[1], os_error_message,
726 strlen(os_error_message) + 1);
727 }
728 close(exec_control_[1]);
729
730 // We avoid running through registered atexit() handlers because that is
731 // unnecessary work.
732 _exit(1);
733 }
734
735 void ReportPid(int pid) {
736 // In the case of starting a detached process the actual pid of that process
737 // is communicated using the exec control pipe.
738 int bytes_written =
739 FDUtils::WriteToBlocking(exec_control_[1], &pid, sizeof(pid));
740 ASSERT(bytes_written == sizeof(int));
741 USE(bytes_written);
742 }
743
744 void ReadChildError() {
745 const int kMaxMessageSize = 256;
746 char* message = DartUtils::ScopedCString(kMaxMessageSize);
747 if (message != NULL) {
748 FDUtils::ReadFromBlocking(exec_control_[0], message, kMaxMessageSize);
749 message[kMaxMessageSize - 1] = '\0';
750 *os_error_message_ = message;
751 } else {
752 // Could not get error message. It will be NULL.
753 ASSERT(*os_error_message_ == NULL);
754 }
755 }
756
757 void ClosePipe(int* fds) {
758 for (int i = 0; i < 2; i++) {
759 if (fds[i] != -1) {
760 close(fds[i]);
761 fds[i] = -1;
762 }
763 }
764 }
765
766 void CloseAllPipes() {
767 ClosePipe(exec_control_);
768 ClosePipe(read_in_);
769 ClosePipe(read_err_);
770 ClosePipe(write_out_);
771 }
772
773 int read_in_[2]; // Pipe for stdout to child process.
774 int read_err_[2]; // Pipe for stderr to child process.
775 int write_out_[2]; // Pipe for stdin to child process.
776 int exec_control_[2]; // Pipe to get the result from exec.
777
778 char** program_arguments_;
779 char** program_environment_;
780
781 Namespace* namespc_;
782 const char* path_;
783 const char* working_directory_;
784 ProcessStartMode mode_;
785 intptr_t* in_;
786 intptr_t* out_;
787 intptr_t* err_;
788 intptr_t* id_;
789 intptr_t* exit_event_;
790 char** os_error_message_;
791
792 DISALLOW_ALLOCATION();
793 DISALLOW_IMPLICIT_CONSTRUCTORS(ProcessStarter);
794};
795
796int Process::Start(Namespace* namespc,
797 const char* path,
798 char* arguments[],
799 intptr_t arguments_length,
800 const char* working_directory,
801 char* environment[],
802 intptr_t environment_length,
803 ProcessStartMode mode,
804 intptr_t* in,
805 intptr_t* out,
806 intptr_t* err,
807 intptr_t* id,
808 intptr_t* exit_event,
809 char** os_error_message) {
810 ProcessStarter starter(namespc, path, arguments, arguments_length,
811 working_directory, environment, environment_length,
812 mode, in, out, err, id, exit_event, os_error_message);
813 return starter.Start();
814}
815
816static bool CloseProcessBuffers(struct pollfd* fds, int alive) {
817 int e = errno;
818 for (int i = 0; i < alive; i++) {
819 close(fds[i].fd);
820 }
821 errno = e;
822 return false;
823}
824
825bool Process::Wait(intptr_t pid,
826 intptr_t in,
827 intptr_t out,
828 intptr_t err,
829 intptr_t exit_event,
830 ProcessResult* result) {
831 // Close input to the process right away.
832 close(in);
833
834 // There is no return from this function using Dart_PropagateError
835 // as memory used by the buffer lists is freed through their
836 // destructors.
837 BufferList out_data;
838 BufferList err_data;
839 union {
840 uint8_t bytes[8];
841 int32_t ints[2];
842 } exit_code_data;
843
844 struct pollfd fds[3];
845 fds[0].fd = out;
846 fds[1].fd = err;
847 fds[2].fd = exit_event;
848
849 for (int i = 0; i < 3; i++) {
850 fds[i].events = POLLIN;
851 }
852
853 int alive = 3;
854 while (alive > 0) {
855 // Blocking call waiting for events from the child process.
856 if (TEMP_FAILURE_RETRY(poll(fds, alive, -1)) <= 0) {
857 return CloseProcessBuffers(fds, alive);
858 }
859
860 // Process incoming data.
861 for (int i = 0; i < alive; i++) {
862 if ((fds[i].revents & (POLLNVAL | POLLERR)) != 0) {
863 return CloseProcessBuffers(fds, alive);
864 }
865 if ((fds[i].revents & POLLIN) != 0) {
866 intptr_t avail = FDUtils::AvailableBytes(fds[i].fd);
867 if (fds[i].fd == out) {
868 if (!out_data.Read(out, avail)) {
869 return CloseProcessBuffers(fds, alive);
870 }
871 } else if (fds[i].fd == err) {
872 if (!err_data.Read(err, avail)) {
873 return CloseProcessBuffers(fds, alive);
874 }
875 } else if (fds[i].fd == exit_event) {
876 if (avail == 8) {
877 intptr_t b =
878 TEMP_FAILURE_RETRY(read(exit_event, exit_code_data.bytes, 8));
879 if (b != 8) {
880 return CloseProcessBuffers(fds, alive);
881 }
882 }
883 } else {
884 UNREACHABLE();
885 }
886 }
887 if ((fds[i].revents & POLLHUP) != 0) {
888 // Remove the pollfd from the list of pollfds.
889 close(fds[i].fd);
890 alive--;
891 if (i < alive) {
892 fds[i] = fds[alive];
893 }
894 // Process the same index again.
895 i--;
896 continue;
897 }
898 }
899 }
900
901 // All handles closed and all data read.
902 result->set_stdout_data(out_data.GetData());
903 result->set_stderr_data(err_data.GetData());
904 DEBUG_ASSERT(out_data.IsEmpty());
905 DEBUG_ASSERT(err_data.IsEmpty());
906
907 // Calculate the exit code.
908 intptr_t exit_code = exit_code_data.ints[0];
909 intptr_t negative = exit_code_data.ints[1];
910 if (negative != 0) {
911 exit_code = -exit_code;
912 }
913 result->set_exit_code(exit_code);
914
915 return true;
916}
917
918bool Process::Kill(intptr_t id, int signal) {
919 return (TEMP_FAILURE_RETRY(kill(id, signal)) != -1);
920}
921
922void Process::TerminateExitCodeHandler() {
923 ExitCodeHandler::TerminateExitCodeThread();
924}
925
926intptr_t Process::CurrentProcessId() {
927 return static_cast<intptr_t>(getpid());
928}
929
930static void SaveErrorAndClose(FILE* file) {
931 int actual_errno = errno;
932 fclose(file);
933 errno = actual_errno;
934}
935
936int64_t Process::CurrentRSS() {
937 // The second value in /proc/self/statm is the current RSS in pages.
938 // It is not possible to use getrusage() because the interested fields are not
939 // implemented by the linux kernel.
940 FILE* statm = fopen("/proc/self/statm", "r");
941 if (statm == NULL) {
942 return -1;
943 }
944 int64_t current_rss_pages = 0;
945 int matches = fscanf(statm, "%*s%" Pd64 "", &current_rss_pages);
946 if (matches != 1) {
947 SaveErrorAndClose(statm);
948 return -1;
949 }
950 fclose(statm);
951 return current_rss_pages * getpagesize();
952}
953
954int64_t Process::MaxRSS() {
955 struct rusage usage;
956 usage.ru_maxrss = 0;
957 int r = getrusage(RUSAGE_SELF, &usage);
958 if (r < 0) {
959 return -1;
960 }
961 return usage.ru_maxrss * KB;
962}
963
964static Mutex* signal_mutex = nullptr;
965static SignalInfo* signal_handlers = NULL;
966static const int kSignalsCount = 7;
967static const int kSignals[kSignalsCount] = {
968 SIGHUP, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGWINCH,
969 SIGQUIT // Allow VMService to listen on SIGQUIT.
970};
971
972SignalInfo::~SignalInfo() {
973 close(fd_);
974}
975
976static void SignalHandler(int signal) {
977 MutexLocker lock(signal_mutex);
978 const SignalInfo* handler = signal_handlers;
979 while (handler != NULL) {
980 if (handler->signal() == signal) {
981 int value = 0;
982 VOID_TEMP_FAILURE_RETRY(write(handler->fd(), &value, 1));
983 }
984 handler = handler->next();
985 }
986}
987
988intptr_t Process::SetSignalHandler(intptr_t signal) {
989 bool found = false;
990 for (int i = 0; i < kSignalsCount; i++) {
991 if (kSignals[i] == signal) {
992 found = true;
993 break;
994 }
995 }
996 if (!found) {
997 return -1;
998 }
999 int fds[2];
1000 if (NO_RETRY_EXPECTED(pipe2(fds, O_CLOEXEC)) != 0) {
1001 return -1;
1002 }
1003 if (!FDUtils::SetNonBlocking(fds[0])) {
1004 close(fds[0]);
1005 close(fds[1]);
1006 return -1;
1007 }
1008 ThreadSignalBlocker blocker(kSignalsCount, kSignals);
1009 MutexLocker lock(signal_mutex);
1010 SignalInfo* handler = signal_handlers;
1011 bool listen = true;
1012 while (handler != NULL) {
1013 if (handler->signal() == signal) {
1014 listen = false;
1015 break;
1016 }
1017 handler = handler->next();
1018 }
1019 if (listen) {
1020 struct sigaction act = {};
1021 act.sa_handler = SignalHandler;
1022 sigemptyset(&act.sa_mask);
1023 for (int i = 0; i < kSignalsCount; i++) {
1024 sigaddset(&act.sa_mask, kSignals[i]);
1025 }
1026 int status = NO_RETRY_EXPECTED(sigaction(signal, &act, NULL));
1027 if (status < 0) {
1028 close(fds[0]);
1029 close(fds[1]);
1030 return -1;
1031 }
1032 }
1033 signal_handlers = new SignalInfo(fds[1], signal, signal_handlers);
1034 return fds[0];
1035}
1036
1037void Process::ClearSignalHandler(intptr_t signal, Dart_Port port) {
1038 ThreadSignalBlocker blocker(kSignalsCount, kSignals);
1039 MutexLocker lock(signal_mutex);
1040 SignalInfo* handler = signal_handlers;
1041 bool unlisten = true;
1042 while (handler != NULL) {
1043 bool remove = false;
1044 if (handler->signal() == signal) {
1045 if ((port == ILLEGAL_PORT) || (handler->port() == port)) {
1046 if (signal_handlers == handler) {
1047 signal_handlers = handler->next();
1048 }
1049 handler->Unlink();
1050 remove = true;
1051 } else {
1052 unlisten = false;
1053 }
1054 }
1055 SignalInfo* next = handler->next();
1056 if (remove) {
1057 delete handler;
1058 }
1059 handler = next;
1060 }
1061 if (unlisten) {
1062 struct sigaction act = {};
1063 act.sa_handler = SIG_DFL;
1064 VOID_NO_RETRY_EXPECTED(sigaction(signal, &act, NULL));
1065 }
1066}
1067
1068void Process::ClearSignalHandlerByFd(intptr_t fd, Dart_Port port) {
1069 ThreadSignalBlocker blocker(kSignalsCount, kSignals);
1070 MutexLocker lock(signal_mutex);
1071 SignalInfo* handler = signal_handlers;
1072 bool unlisten = true;
1073 intptr_t signal = -1;
1074 while (handler != NULL) {
1075 bool remove = false;
1076 if (handler->fd() == fd) {
1077 if ((port == ILLEGAL_PORT) || (handler->port() == port)) {
1078 if (signal_handlers == handler) {
1079 signal_handlers = handler->next();
1080 }
1081 handler->Unlink();
1082 remove = true;
1083 signal = handler->signal();
1084 } else {
1085 unlisten = false;
1086 }
1087 }
1088 SignalInfo* next = handler->next();
1089 if (remove) {
1090 delete handler;
1091 }
1092 handler = next;
1093 }
1094 if (unlisten && (signal != -1)) {
1095 struct sigaction act = {};
1096 act.sa_handler = SIG_DFL;
1097 VOID_NO_RETRY_EXPECTED(sigaction(signal, &act, NULL));
1098 }
1099}
1100
1101void ProcessInfoList::Init() {
1102 ASSERT(ProcessInfoList::mutex_ == nullptr);
1103 ProcessInfoList::mutex_ = new Mutex();
1104}
1105
1106void ProcessInfoList::Cleanup() {
1107 ASSERT(ProcessInfoList::mutex_ != nullptr);
1108 delete ProcessInfoList::mutex_;
1109 ProcessInfoList::mutex_ = nullptr;
1110}
1111
1112void ExitCodeHandler::Init() {
1113 ASSERT(ExitCodeHandler::monitor_ == nullptr);
1114 ExitCodeHandler::monitor_ = new Monitor();
1115}
1116
1117void ExitCodeHandler::Cleanup() {
1118 ASSERT(ExitCodeHandler::monitor_ != nullptr);
1119 delete ExitCodeHandler::monitor_;
1120 ExitCodeHandler::monitor_ = nullptr;
1121}
1122
1123void Process::Init() {
1124 ExitCodeHandler::Init();
1125 ProcessInfoList::Init();
1126
1127 ASSERT(signal_mutex == nullptr);
1128 signal_mutex = new Mutex();
1129
1130 ASSERT(Process::global_exit_code_mutex_ == nullptr);
1131 Process::global_exit_code_mutex_ = new Mutex();
1132}
1133
1134void Process::Cleanup() {
1135 ClearAllSignalHandlers();
1136
1137 ASSERT(signal_mutex != nullptr);
1138 delete signal_mutex;
1139 signal_mutex = nullptr;
1140
1141 ASSERT(Process::global_exit_code_mutex_ != nullptr);
1142 delete Process::global_exit_code_mutex_;
1143 Process::global_exit_code_mutex_ = nullptr;
1144
1145 ProcessInfoList::Cleanup();
1146 ExitCodeHandler::Cleanup();
1147}
1148
1149} // namespace bin
1150} // namespace dart
1151
1152#endif // defined(HOST_OS_ANDROID)
1153