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_LINUX)
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/resource.h> // NOLINT
17#include <sys/wait.h> // NOLINT
18#include <unistd.h> // NOLINT
19
20#include "bin/dartutils.h"
21#include "bin/directory.h"
22#include "bin/fdutils.h"
23#include "bin/file.h"
24#include "bin/lockers.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(openat64(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 if (program_environment_ != NULL) {
556 environ = program_environment_;
557 }
558
559 // Report the final PID and do the exec.
560 ReportPid(getpid()); // getpid cannot fail.
561 char realpath[PATH_MAX];
562 if (!FindPathInNamespace(realpath, PATH_MAX)) {
563 ReportChildError();
564 }
565 // TODO(dart:io) Test for the existence of execveat, and use it
566 // instead.
567 execvp(realpath, const_cast<char* const*>(program_arguments_));
568 ReportChildError();
569 } else {
570 // Exit the intermediate process.
571 exit(0);
572 }
573 }
574 } else {
575 // Exit the intermediate process.
576 exit(0);
577 }
578 }
579
580 int RegisterProcess(pid_t pid) {
581 int result;
582 int event_fds[2];
583 result = TEMP_FAILURE_RETRY(pipe2(event_fds, O_CLOEXEC));
584 if (result < 0) {
585 return CleanupAndReturnError();
586 }
587
588 ProcessInfoList::AddProcess(pid, event_fds[1]);
589 *exit_event_ = event_fds[0];
590 FDUtils::SetNonBlocking(event_fds[0]);
591 return 0;
592 }
593
594 int ReadExecResult() {
595 int child_errno;
596 int bytes_read = -1;
597 // Read exec result from child. If no data is returned the exec was
598 // successful and the exec call closed the pipe. Otherwise the errno
599 // is written to the pipe.
600 bytes_read = FDUtils::ReadFromBlocking(exec_control_[0], &child_errno,
601 sizeof(child_errno));
602 if (bytes_read == sizeof(child_errno)) {
603 ReadChildError();
604 return child_errno;
605 } else if (bytes_read == -1) {
606 return errno;
607 }
608 return 0;
609 }
610
611 int ReadDetachedExecResult(pid_t* pid) {
612 int child_errno;
613 int bytes_read = -1;
614 // Read exec result from child. If only pid data is returned the exec was
615 // successful and the exec call closed the pipe. Otherwise the errno
616 // is written to the pipe as well.
617 int result[2];
618 bytes_read =
619 FDUtils::ReadFromBlocking(exec_control_[0], result, sizeof(result));
620 if (bytes_read == sizeof(int)) {
621 *pid = result[0];
622 } else if (bytes_read == 2 * sizeof(int)) {
623 *pid = result[0];
624 child_errno = result[1];
625 ReadChildError();
626 return child_errno;
627 } else if (bytes_read == -1) {
628 return errno;
629 }
630 return 0;
631 }
632
633 void SetupDetached() {
634 ASSERT(mode_ == kDetached);
635
636 // Close all open file descriptors except for exec_control_[1].
637 int max_fds = sysconf(_SC_OPEN_MAX);
638 if (max_fds == -1) {
639 max_fds = _POSIX_OPEN_MAX;
640 }
641 for (int fd = 0; fd < max_fds; fd++) {
642 if (fd != exec_control_[1]) {
643 close(fd);
644 }
645 }
646
647 // Re-open stdin, stdout and stderr and connect them to /dev/null.
648 // The loop above should already have closed all of them, so
649 // creating new file descriptors should start at STDIN_FILENO.
650 int fd = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
651 if (fd != STDIN_FILENO) {
652 ReportChildError();
653 }
654 if (TEMP_FAILURE_RETRY(dup2(STDIN_FILENO, STDOUT_FILENO)) !=
655 STDOUT_FILENO) {
656 ReportChildError();
657 }
658 if (TEMP_FAILURE_RETRY(dup2(STDIN_FILENO, STDERR_FILENO)) !=
659 STDERR_FILENO) {
660 ReportChildError();
661 }
662 }
663
664 void SetupDetachedWithStdio() {
665 // Close all open file descriptors except for
666 // exec_control_[1], write_out_[0], read_in_[1] and
667 // read_err_[1].
668 int max_fds = sysconf(_SC_OPEN_MAX);
669 if (max_fds == -1) {
670 max_fds = _POSIX_OPEN_MAX;
671 }
672 for (int fd = 0; fd < max_fds; fd++) {
673 if ((fd != exec_control_[1]) && (fd != write_out_[0]) &&
674 (fd != read_in_[1]) && (fd != read_err_[1])) {
675 close(fd);
676 }
677 }
678
679 if (TEMP_FAILURE_RETRY(dup2(write_out_[0], STDIN_FILENO)) == -1) {
680 ReportChildError();
681 }
682 close(write_out_[0]);
683
684 if (TEMP_FAILURE_RETRY(dup2(read_in_[1], STDOUT_FILENO)) == -1) {
685 ReportChildError();
686 }
687 close(read_in_[1]);
688
689 if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) {
690 ReportChildError();
691 }
692 close(read_err_[1]);
693 }
694
695 int CleanupAndReturnError() {
696 int actual_errno = errno;
697 // If CleanupAndReturnError is called without an actual errno make
698 // sure to return an error anyway.
699 if (actual_errno == 0) {
700 actual_errno = EPERM;
701 }
702 SetChildOsErrorMessage();
703 CloseAllPipes();
704 return actual_errno;
705 }
706
707 void SetChildOsErrorMessage() {
708 const int kBufferSize = 1024;
709 char* error_message = DartUtils::ScopedCString(kBufferSize);
710 Utils::StrError(errno, error_message, kBufferSize);
711 *os_error_message_ = error_message;
712 }
713
714 void ReportChildError() {
715 // In the case of failure in the child process write the errno and
716 // the OS error message to the exec control pipe and exit.
717 int child_errno = errno;
718 const int kBufferSize = 1024;
719 char error_buf[kBufferSize];
720 char* os_error_message = Utils::StrError(errno, error_buf, kBufferSize);
721 int bytes_written = FDUtils::WriteToBlocking(exec_control_[1], &child_errno,
722 sizeof(child_errno));
723 if (bytes_written == sizeof(child_errno)) {
724 FDUtils::WriteToBlocking(exec_control_[1], os_error_message,
725 strlen(os_error_message) + 1);
726 }
727 close(exec_control_[1]);
728
729 // We avoid running through registered atexit() handlers because that is
730 // unnecessary work.
731 _exit(1);
732 }
733
734 void ReportPid(int pid) {
735 // In the case of starting a detached process the actual pid of that process
736 // is communicated using the exec control pipe.
737 int bytes_written =
738 FDUtils::WriteToBlocking(exec_control_[1], &pid, sizeof(pid));
739 ASSERT(bytes_written == sizeof(int));
740 USE(bytes_written);
741 }
742
743 void ReadChildError() {
744 const int kMaxMessageSize = 256;
745 char* message = DartUtils::ScopedCString(kMaxMessageSize);
746 if (message != NULL) {
747 FDUtils::ReadFromBlocking(exec_control_[0], message, kMaxMessageSize);
748 message[kMaxMessageSize - 1] = '\0';
749 *os_error_message_ = message;
750 } else {
751 // Could not get error message. It will be NULL.
752 ASSERT(*os_error_message_ == NULL);
753 }
754 }
755
756 void ClosePipe(int* fds) {
757 for (int i = 0; i < 2; i++) {
758 if (fds[i] != -1) {
759 close(fds[i]);
760 fds[i] = -1;
761 }
762 }
763 }
764
765 void CloseAllPipes() {
766 ClosePipe(exec_control_);
767 ClosePipe(read_in_);
768 ClosePipe(read_err_);
769 ClosePipe(write_out_);
770 }
771
772 int read_in_[2]; // Pipe for stdout to child process.
773 int read_err_[2]; // Pipe for stderr to child process.
774 int write_out_[2]; // Pipe for stdin to child process.
775 int exec_control_[2]; // Pipe to get the result from exec.
776
777 char** program_arguments_;
778 char** program_environment_;
779
780 Namespace* namespc_;
781 const char* path_;
782 const char* working_directory_;
783 ProcessStartMode mode_;
784 intptr_t* in_;
785 intptr_t* out_;
786 intptr_t* err_;
787 intptr_t* id_;
788 intptr_t* exit_event_;
789 char** os_error_message_;
790
791 DISALLOW_ALLOCATION();
792 DISALLOW_IMPLICIT_CONSTRUCTORS(ProcessStarter);
793};
794
795int Process::Start(Namespace* namespc,
796 const char* path,
797 char* arguments[],
798 intptr_t arguments_length,
799 const char* working_directory,
800 char* environment[],
801 intptr_t environment_length,
802 ProcessStartMode mode,
803 intptr_t* in,
804 intptr_t* out,
805 intptr_t* err,
806 intptr_t* id,
807 intptr_t* exit_event,
808 char** os_error_message) {
809 ProcessStarter starter(namespc, path, arguments, arguments_length,
810 working_directory, environment, environment_length,
811 mode, in, out, err, id, exit_event, os_error_message);
812 return starter.Start();
813}
814
815static bool CloseProcessBuffers(struct pollfd* fds, int alive) {
816 int e = errno;
817 for (int i = 0; i < alive; i++) {
818 close(fds[i].fd);
819 }
820 errno = e;
821 return false;
822}
823
824bool Process::Wait(intptr_t pid,
825 intptr_t in,
826 intptr_t out,
827 intptr_t err,
828 intptr_t exit_event,
829 ProcessResult* result) {
830 // Close input to the process right away.
831 close(in);
832
833 // There is no return from this function using Dart_PropagateError
834 // as memory used by the buffer lists is freed through their
835 // destructors.
836 BufferList out_data;
837 BufferList err_data;
838 union {
839 uint8_t bytes[8];
840 int32_t ints[2];
841 } exit_code_data;
842
843 struct pollfd fds[3];
844 fds[0].fd = out;
845 fds[1].fd = err;
846 fds[2].fd = exit_event;
847
848 for (int i = 0; i < 3; i++) {
849 fds[i].events = POLLIN;
850 }
851
852 int alive = 3;
853 while (alive > 0) {
854 // Blocking call waiting for events from the child process.
855 if (TEMP_FAILURE_RETRY(poll(fds, alive, -1)) <= 0) {
856 return CloseProcessBuffers(fds, alive);
857 }
858
859 // Process incoming data.
860 for (int i = 0; i < alive; i++) {
861 if ((fds[i].revents & (POLLNVAL | POLLERR)) != 0) {
862 return CloseProcessBuffers(fds, alive);
863 }
864 if ((fds[i].revents & POLLIN) != 0) {
865 intptr_t avail = FDUtils::AvailableBytes(fds[i].fd);
866 if (fds[i].fd == out) {
867 if (!out_data.Read(out, avail)) {
868 return CloseProcessBuffers(fds, alive);
869 }
870 } else if (fds[i].fd == err) {
871 if (!err_data.Read(err, avail)) {
872 return CloseProcessBuffers(fds, alive);
873 }
874 } else if (fds[i].fd == exit_event) {
875 if (avail == 8) {
876 intptr_t b =
877 TEMP_FAILURE_RETRY(read(exit_event, exit_code_data.bytes, 8));
878 if (b != 8) {
879 return CloseProcessBuffers(fds, alive);
880 }
881 }
882 } else {
883 UNREACHABLE();
884 }
885 }
886 if ((fds[i].revents & POLLHUP) != 0) {
887 // Remove the pollfd from the list of pollfds.
888 close(fds[i].fd);
889 alive--;
890 if (i < alive) {
891 fds[i] = fds[alive];
892 }
893 // Process the same index again.
894 i--;
895 continue;
896 }
897 }
898 }
899
900 // All handles closed and all data read.
901 result->set_stdout_data(out_data.GetData());
902 result->set_stderr_data(err_data.GetData());
903 DEBUG_ASSERT(out_data.IsEmpty());
904 DEBUG_ASSERT(err_data.IsEmpty());
905
906 // Calculate the exit code.
907 intptr_t exit_code = exit_code_data.ints[0];
908 intptr_t negative = exit_code_data.ints[1];
909 if (negative != 0) {
910 exit_code = -exit_code;
911 }
912 result->set_exit_code(exit_code);
913
914 return true;
915}
916
917bool Process::Kill(intptr_t id, int signal) {
918 return (TEMP_FAILURE_RETRY(kill(id, signal)) != -1);
919}
920
921void Process::TerminateExitCodeHandler() {
922 ExitCodeHandler::TerminateExitCodeThread();
923}
924
925intptr_t Process::CurrentProcessId() {
926 return static_cast<intptr_t>(getpid());
927}
928
929static void SaveErrorAndClose(FILE* file) {
930 int actual_errno = errno;
931 fclose(file);
932 errno = actual_errno;
933}
934
935int64_t Process::CurrentRSS() {
936 // The second value in /proc/self/statm is the current RSS in pages.
937 // It is not possible to use getrusage() because the interested fields are not
938 // implemented by the linux kernel.
939 FILE* statm = fopen("/proc/self/statm", "r");
940 if (statm == NULL) {
941 return -1;
942 }
943 int64_t current_rss_pages = 0;
944 int matches = fscanf(statm, "%*s%" Pd64 "", &current_rss_pages);
945 if (matches != 1) {
946 SaveErrorAndClose(statm);
947 return -1;
948 }
949 fclose(statm);
950 return current_rss_pages * getpagesize();
951}
952
953int64_t Process::MaxRSS() {
954 struct rusage usage;
955 usage.ru_maxrss = 0;
956 int r = getrusage(RUSAGE_SELF, &usage);
957 if (r < 0) {
958 return -1;
959 }
960 return usage.ru_maxrss * KB;
961}
962
963static Mutex* signal_mutex = nullptr;
964static SignalInfo* signal_handlers = NULL;
965static const int kSignalsCount = 7;
966static const int kSignals[kSignalsCount] = {
967 SIGHUP, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGWINCH,
968 SIGQUIT // Allow VMService to listen on SIGQUIT.
969};
970
971SignalInfo::~SignalInfo() {
972 close(fd_);
973}
974
975static void SignalHandler(int signal) {
976 MutexLocker lock(signal_mutex);
977 const SignalInfo* handler = signal_handlers;
978 while (handler != NULL) {
979 if (handler->signal() == signal) {
980 int value = 0;
981 VOID_TEMP_FAILURE_RETRY(write(handler->fd(), &value, 1));
982 }
983 handler = handler->next();
984 }
985}
986
987intptr_t Process::SetSignalHandler(intptr_t signal) {
988 bool found = false;
989 for (int i = 0; i < kSignalsCount; i++) {
990 if (kSignals[i] == signal) {
991 found = true;
992 break;
993 }
994 }
995 if (!found) {
996 return -1;
997 }
998 int fds[2];
999 if (NO_RETRY_EXPECTED(pipe2(fds, O_CLOEXEC)) != 0) {
1000 return -1;
1001 }
1002 ThreadSignalBlocker blocker(kSignalsCount, kSignals);
1003 MutexLocker lock(signal_mutex);
1004 SignalInfo* handler = signal_handlers;
1005 bool listen = true;
1006 while (handler != NULL) {
1007 if (handler->signal() == signal) {
1008 listen = false;
1009 break;
1010 }
1011 handler = handler->next();
1012 }
1013 if (listen) {
1014 struct sigaction act = {};
1015 act.sa_handler = SignalHandler;
1016 sigemptyset(&act.sa_mask);
1017 for (int i = 0; i < kSignalsCount; i++) {
1018 sigaddset(&act.sa_mask, kSignals[i]);
1019 }
1020 int status = NO_RETRY_EXPECTED(sigaction(signal, &act, NULL));
1021 if (status < 0) {
1022 int err = errno;
1023 close(fds[0]);
1024 close(fds[1]);
1025 errno = err;
1026 return -1;
1027 }
1028 }
1029 signal_handlers = new SignalInfo(fds[1], signal, signal_handlers);
1030 return fds[0];
1031}
1032
1033void Process::ClearSignalHandler(intptr_t signal, Dart_Port port) {
1034 ThreadSignalBlocker blocker(kSignalsCount, kSignals);
1035 MutexLocker lock(signal_mutex);
1036 SignalInfo* handler = signal_handlers;
1037 bool unlisten = true;
1038 while (handler != NULL) {
1039 bool remove = false;
1040 if (handler->signal() == signal) {
1041 if ((port == ILLEGAL_PORT) || (handler->port() == port)) {
1042 if (signal_handlers == handler) {
1043 signal_handlers = handler->next();
1044 }
1045 handler->Unlink();
1046 remove = true;
1047 } else {
1048 unlisten = false;
1049 }
1050 }
1051 SignalInfo* next = handler->next();
1052 if (remove) {
1053 delete handler;
1054 }
1055 handler = next;
1056 }
1057 if (unlisten) {
1058 struct sigaction act = {};
1059 act.sa_handler = SIG_DFL;
1060 VOID_NO_RETRY_EXPECTED(sigaction(signal, &act, NULL));
1061 }
1062}
1063
1064void Process::ClearSignalHandlerByFd(intptr_t fd, Dart_Port port) {
1065 ThreadSignalBlocker blocker(kSignalsCount, kSignals);
1066 MutexLocker lock(signal_mutex);
1067 SignalInfo* handler = signal_handlers;
1068 bool unlisten = true;
1069 intptr_t signal = -1;
1070 while (handler != NULL) {
1071 bool remove = false;
1072 if (handler->fd() == fd) {
1073 if ((port == ILLEGAL_PORT) || (handler->port() == port)) {
1074 if (signal_handlers == handler) {
1075 signal_handlers = handler->next();
1076 }
1077 handler->Unlink();
1078 remove = true;
1079 signal = handler->signal();
1080 } else {
1081 unlisten = false;
1082 }
1083 }
1084 SignalInfo* next = handler->next();
1085 if (remove) {
1086 delete handler;
1087 }
1088 handler = next;
1089 }
1090 if (unlisten && (signal != -1)) {
1091 struct sigaction act = {};
1092 act.sa_handler = SIG_DFL;
1093 VOID_NO_RETRY_EXPECTED(sigaction(signal, &act, NULL));
1094 }
1095}
1096
1097void ProcessInfoList::Init() {
1098 ASSERT(ProcessInfoList::mutex_ == nullptr);
1099 ProcessInfoList::mutex_ = new Mutex();
1100}
1101
1102void ProcessInfoList::Cleanup() {
1103 ASSERT(ProcessInfoList::mutex_ != nullptr);
1104 delete ProcessInfoList::mutex_;
1105 ProcessInfoList::mutex_ = nullptr;
1106}
1107
1108void ExitCodeHandler::Init() {
1109 ASSERT(ExitCodeHandler::monitor_ == nullptr);
1110 ExitCodeHandler::monitor_ = new Monitor();
1111}
1112
1113void ExitCodeHandler::Cleanup() {
1114 ASSERT(ExitCodeHandler::monitor_ != nullptr);
1115 delete ExitCodeHandler::monitor_;
1116 ExitCodeHandler::monitor_ = nullptr;
1117}
1118
1119void Process::Init() {
1120 ExitCodeHandler::Init();
1121 ProcessInfoList::Init();
1122
1123 ASSERT(signal_mutex == nullptr);
1124 signal_mutex = new Mutex();
1125
1126 ASSERT(Process::global_exit_code_mutex_ == nullptr);
1127 Process::global_exit_code_mutex_ = new Mutex();
1128}
1129
1130void Process::Cleanup() {
1131 ClearAllSignalHandlers();
1132
1133 ASSERT(signal_mutex != nullptr);
1134 delete signal_mutex;
1135 signal_mutex = nullptr;
1136
1137 ASSERT(Process::global_exit_code_mutex_ != nullptr);
1138 delete Process::global_exit_code_mutex_;
1139 Process::global_exit_code_mutex_ = nullptr;
1140
1141 ProcessInfoList::Cleanup();
1142 ExitCodeHandler::Cleanup();
1143}
1144
1145} // namespace bin
1146} // namespace dart
1147
1148#endif // defined(HOST_OS_LINUX)
1149