OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "platform/globals.h" | 5 #include "platform/globals.h" |
6 #if defined(TARGET_OS_ANDROID) | 6 #if defined(TARGET_OS_ANDROID) |
7 | 7 |
8 #include "bin/process.h" | 8 #include "bin/process.h" |
9 | 9 |
10 #include <errno.h> // NOLINT | 10 #include <errno.h> // NOLINT |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
231 | 231 |
232 | 232 |
233 class ProcessStarter { | 233 class ProcessStarter { |
234 public: | 234 public: |
235 ProcessStarter(const char* path, | 235 ProcessStarter(const char* path, |
236 char* arguments[], | 236 char* arguments[], |
237 intptr_t arguments_length, | 237 intptr_t arguments_length, |
238 const char* working_directory, | 238 const char* working_directory, |
239 char* environment[], | 239 char* environment[], |
240 intptr_t environment_length, | 240 intptr_t environment_length, |
241 bool detach, | 241 ProcessStartMode mode, |
242 intptr_t* in, | 242 intptr_t* in, |
243 intptr_t* out, | 243 intptr_t* out, |
244 intptr_t* err, | 244 intptr_t* err, |
245 intptr_t* id, | 245 intptr_t* id, |
246 intptr_t* exit_event, | 246 intptr_t* exit_event, |
247 char** os_error_message) | 247 char** os_error_message) |
248 : path_(path), | 248 : path_(path), |
249 working_directory_(working_directory), | 249 working_directory_(working_directory), |
250 detach_(detach), | 250 mode_(mode), |
251 in_(in), | 251 in_(in), |
252 out_(out), | 252 out_(out), |
253 err_(err), | 253 err_(err), |
254 id_(id), | 254 id_(id), |
255 exit_event_(exit_event), | 255 exit_event_(exit_event), |
256 os_error_message_(os_error_message) { | 256 os_error_message_(os_error_message) { |
257 read_in_[0] = -1; | 257 read_in_[0] = -1; |
258 read_in_[1] = -1; | 258 read_in_[1] = -1; |
259 read_err_[0] = -1; | 259 read_err_[0] = -1; |
260 read_err_[1] = -1; | 260 read_err_[1] = -1; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
301 // This runs in the new process. | 301 // This runs in the new process. |
302 NewProcess(); | 302 NewProcess(); |
303 } | 303 } |
304 | 304 |
305 // This runs in the original process. | 305 // This runs in the original process. |
306 | 306 |
307 // Be sure to listen for exit-codes, now we have a child-process. | 307 // Be sure to listen for exit-codes, now we have a child-process. |
308 ExitCodeHandler::ProcessStarted(); | 308 ExitCodeHandler::ProcessStarted(); |
309 | 309 |
310 // Register the child process if not detached. | 310 // Register the child process if not detached. |
311 if (!detach_) { | 311 if (mode_ == kNormal) { |
312 err = RegisterProcess(pid); | 312 err = RegisterProcess(pid); |
313 if (err != 0) return err; | 313 if (err != 0) return err; |
314 } | 314 } |
315 | 315 |
316 // Notify child process to start. This is done to delay the call to exec | 316 // Notify child process to start. This is done to delay the call to exec |
317 // until the process is registered above, and we are ready to receive the | 317 // until the process is registered above, and we are ready to receive the |
318 // exit code. | 318 // exit code. |
319 char msg = '1'; | 319 char msg = '1'; |
320 int bytes_written = | 320 int bytes_written = |
321 FDUtils::WriteToBlocking(read_in_[1], &msg, sizeof(msg)); | 321 FDUtils::WriteToBlocking(read_in_[1], &msg, sizeof(msg)); |
322 if (bytes_written != sizeof(msg)) { | 322 if (bytes_written != sizeof(msg)) { |
323 return CleanupAndReturnError(); | 323 return CleanupAndReturnError(); |
324 } | 324 } |
325 | 325 |
326 // Read the result of executing the child process. | 326 // Read the result of executing the child process. |
327 VOID_TEMP_FAILURE_RETRY(close(exec_control_[1])); | 327 VOID_TEMP_FAILURE_RETRY(close(exec_control_[1])); |
328 exec_control_[1] = -1; | 328 exec_control_[1] = -1; |
329 if (!detach_) { | 329 if (mode_ == kNormal) { |
330 err = ReadExecResult(); | 330 err = ReadExecResult(); |
331 } else { | 331 } else { |
332 err = ReadDetachedExecResult(&pid); | 332 err = ReadDetachedExecResult(&pid); |
333 } | 333 } |
334 VOID_TEMP_FAILURE_RETRY(close(exec_control_[0])); | 334 VOID_TEMP_FAILURE_RETRY(close(exec_control_[0])); |
335 exec_control_[0] = -1; | 335 exec_control_[0] = -1; |
336 | 336 |
337 // Return error code if any failures. | 337 // Return error code if any failures. |
338 if (err != 0) { | 338 if (err != 0) { |
339 if (!detach_) { | 339 if (mode_ == kNormal) { |
340 // Since exec() failed, we're not interested in the exit code. | 340 // Since exec() failed, we're not interested in the exit code. |
341 // We close the reading side of the exit code pipe here. | 341 // We close the reading side of the exit code pipe here. |
342 // GetProcessExitCodes will get a broken pipe error when it | 342 // GetProcessExitCodes will get a broken pipe error when it |
343 // tries to write to the writing side of the pipe and it will | 343 // tries to write to the writing side of the pipe and it will |
344 // ignore the error. | 344 // ignore the error. |
345 VOID_TEMP_FAILURE_RETRY(close(*exit_event_)); | 345 VOID_TEMP_FAILURE_RETRY(close(*exit_event_)); |
346 *exit_event_ = -1; | 346 *exit_event_ = -1; |
347 } | 347 } |
348 CloseAllPipes(); | 348 CloseAllPipes(); |
349 return err; | 349 return err; |
350 } | 350 } |
351 | 351 |
352 if (!detach_) { | 352 if (mode_ != kDetached) { |
353 // Connect stdio, stdout and stderr. | 353 // Connect stdio, stdout and stderr. |
354 FDUtils::SetNonBlocking(read_in_[0]); | 354 FDUtils::SetNonBlocking(read_in_[0]); |
355 *in_ = read_in_[0]; | 355 *in_ = read_in_[0]; |
356 VOID_TEMP_FAILURE_RETRY(close(read_in_[1])); | 356 VOID_TEMP_FAILURE_RETRY(close(read_in_[1])); |
357 FDUtils::SetNonBlocking(write_out_[1]); | 357 FDUtils::SetNonBlocking(write_out_[1]); |
358 *out_ = write_out_[1]; | 358 *out_ = write_out_[1]; |
359 VOID_TEMP_FAILURE_RETRY(close(write_out_[0])); | 359 VOID_TEMP_FAILURE_RETRY(close(write_out_[0])); |
360 FDUtils::SetNonBlocking(read_err_[0]); | 360 FDUtils::SetNonBlocking(read_err_[0]); |
361 *err_ = read_err_[0]; | 361 *err_ = read_err_[0]; |
362 VOID_TEMP_FAILURE_RETRY(close(read_err_[1])); | 362 VOID_TEMP_FAILURE_RETRY(close(read_err_[1])); |
(...skipping 25 matching lines...) Expand all Loading... |
388 | 388 |
389 // For a detached process the pipe to connect stdout is still used for | 389 // For a detached process the pipe to connect stdout is still used for |
390 // signaling when to do the first fork. | 390 // signaling when to do the first fork. |
391 result = TEMP_FAILURE_RETRY(pipe(read_in_)); | 391 result = TEMP_FAILURE_RETRY(pipe(read_in_)); |
392 if (result < 0) { | 392 if (result < 0) { |
393 return CleanupAndReturnError(); | 393 return CleanupAndReturnError(); |
394 } | 394 } |
395 FDUtils::SetCloseOnExec(read_in_[0]); | 395 FDUtils::SetCloseOnExec(read_in_[0]); |
396 | 396 |
397 // For detached processes the pipe to connect stderr and stdin are not used. | 397 // For detached processes the pipe to connect stderr and stdin are not used. |
398 if (!detach_) { | 398 if (mode_ != kDetached) { |
399 result = TEMP_FAILURE_RETRY(pipe(read_err_)); | 399 result = TEMP_FAILURE_RETRY(pipe(read_err_)); |
400 if (result < 0) { | 400 if (result < 0) { |
401 return CleanupAndReturnError(); | 401 return CleanupAndReturnError(); |
402 } | 402 } |
403 FDUtils::SetCloseOnExec(read_err_[0]); | 403 FDUtils::SetCloseOnExec(read_err_[0]); |
404 | 404 |
405 result = TEMP_FAILURE_RETRY(pipe(write_out_)); | 405 result = TEMP_FAILURE_RETRY(pipe(write_out_)); |
406 if (result < 0) { | 406 if (result < 0) { |
407 return CleanupAndReturnError(); | 407 return CleanupAndReturnError(); |
408 } | 408 } |
409 FDUtils::SetCloseOnExec(write_out_[1]); | 409 FDUtils::SetCloseOnExec(write_out_[1]); |
410 } | 410 } |
411 | 411 |
412 return 0; | 412 return 0; |
413 } | 413 } |
414 | 414 |
415 | 415 |
416 void NewProcess() { | 416 void NewProcess() { |
417 // Wait for parent process before setting up the child process. | 417 // Wait for parent process before setting up the child process. |
418 char msg; | 418 char msg; |
419 int bytes_read = FDUtils::ReadFromBlocking(read_in_[0], &msg, sizeof(msg)); | 419 int bytes_read = FDUtils::ReadFromBlocking(read_in_[0], &msg, sizeof(msg)); |
420 if (bytes_read != sizeof(msg)) { | 420 if (bytes_read != sizeof(msg)) { |
421 perror("Failed receiving notification message"); | 421 perror("Failed receiving notification message"); |
422 exit(1); | 422 exit(1); |
423 } | 423 } |
424 if (detach_) { | 424 if (mode_ == kNormal) { |
| 425 ExecProcess(); |
| 426 } else { |
425 ExecDetachedProcess(); | 427 ExecDetachedProcess(); |
426 } else { | |
427 ExecProcess(); | |
428 } | 428 } |
429 } | 429 } |
430 | 430 |
431 | 431 |
432 void ExecProcess() { | 432 void ExecProcess() { |
433 VOID_TEMP_FAILURE_RETRY(close(write_out_[1])); | 433 VOID_TEMP_FAILURE_RETRY(close(write_out_[1])); |
434 VOID_TEMP_FAILURE_RETRY(close(read_in_[0])); | 434 VOID_TEMP_FAILURE_RETRY(close(read_in_[0])); |
435 VOID_TEMP_FAILURE_RETRY(close(read_err_[0])); | 435 VOID_TEMP_FAILURE_RETRY(close(read_err_[0])); |
436 VOID_TEMP_FAILURE_RETRY(close(exec_control_[0])); | 436 VOID_TEMP_FAILURE_RETRY(close(exec_control_[0])); |
437 | 437 |
(...skipping 22 matching lines...) Expand all Loading... |
460 } | 460 } |
461 | 461 |
462 VOID_TEMP_FAILURE_RETRY( | 462 VOID_TEMP_FAILURE_RETRY( |
463 execvp(path_, const_cast<char* const*>(program_arguments_))); | 463 execvp(path_, const_cast<char* const*>(program_arguments_))); |
464 | 464 |
465 ReportChildError(); | 465 ReportChildError(); |
466 } | 466 } |
467 | 467 |
468 | 468 |
469 void ExecDetachedProcess() { | 469 void ExecDetachedProcess() { |
470 ASSERT(write_out_[0] == -1); | 470 if (mode_ == kDetached) { |
471 ASSERT(write_out_[1] == -1); | 471 ASSERT(write_out_[0] == -1); |
472 ASSERT(read_err_[0] == -1); | 472 ASSERT(write_out_[1] == -1); |
473 ASSERT(read_err_[1] == -1); | 473 ASSERT(read_err_[0] == -1); |
474 // For a detached process the pipe to connect stdout is only used for | 474 ASSERT(read_err_[1] == -1); |
475 // signaling when to do the first fork. | 475 // For a detached process the pipe to connect stdout is only used for |
476 VOID_TEMP_FAILURE_RETRY(close(read_in_[0])); | 476 // signaling when to do the first fork. |
477 VOID_TEMP_FAILURE_RETRY(close(read_in_[1])); | 477 VOID_TEMP_FAILURE_RETRY(close(read_in_[0])); |
| 478 read_in_[0] = -1; |
| 479 VOID_TEMP_FAILURE_RETRY(close(read_in_[1])); |
| 480 read_in_[1] = -1; |
| 481 } else { |
| 482 // Don't close any fds if keeping stdio open to the detached process. |
| 483 ASSERT(mode_ == kDetachedWithStdio); |
| 484 } |
478 // Fork once more to start a new session. | 485 // Fork once more to start a new session. |
479 pid_t pid = TEMP_FAILURE_RETRY(fork()); | 486 pid_t pid = TEMP_FAILURE_RETRY(fork()); |
480 if (pid < 0) { | 487 if (pid < 0) { |
481 ReportChildError(); | 488 ReportChildError(); |
482 } else if (pid == 0) { | 489 } else if (pid == 0) { |
483 // Start a new session. | 490 // Start a new session. |
484 if (TEMP_FAILURE_RETRY(setsid()) == -1) { | 491 if (TEMP_FAILURE_RETRY(setsid()) == -1) { |
485 ReportChildError(); | 492 ReportChildError(); |
486 } else { | 493 } else { |
487 // Do a final fork to not be the session leader. | 494 // Do a final fork to not be the session leader. |
488 pid = TEMP_FAILURE_RETRY(fork()); | 495 pid = TEMP_FAILURE_RETRY(fork()); |
489 if (pid < 0) { | 496 if (pid < 0) { |
490 ReportChildError(); | 497 ReportChildError(); |
491 } else if (pid == 0) { | 498 } else if (pid == 0) { |
492 // Close all open file descriptors except for exec_control_[1]. | 499 if (mode_ == kDetached) { |
493 int max_fds = sysconf(_SC_OPEN_MAX); | 500 SetupDetached(); |
494 if (max_fds == -1) max_fds = _POSIX_OPEN_MAX; | 501 } else { |
495 for (int fd = 0; fd < max_fds; fd++) { | 502 SetupDetachedWithStdio(); |
496 if (fd != exec_control_[1]) { | |
497 VOID_TEMP_FAILURE_RETRY(close(fd)); | |
498 } | |
499 } | 503 } |
500 | 504 |
501 // Re-open stdin, stdout and stderr and connect them to /dev/null. | 505 if (working_directory_ != NULL && |
502 // The loop above should already have closed all of them, so | 506 TEMP_FAILURE_RETRY(chdir(working_directory_)) == -1) { |
503 // creating new file descriptors should start at STDIN_FILENO. | |
504 int fd = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)); | |
505 if (fd != STDIN_FILENO) { | |
506 ReportChildError(); | |
507 } | |
508 if (TEMP_FAILURE_RETRY(dup2(STDIN_FILENO, STDOUT_FILENO)) != | |
509 STDOUT_FILENO) { | |
510 ReportChildError(); | |
511 } | |
512 if (TEMP_FAILURE_RETRY(dup2(STDIN_FILENO, STDERR_FILENO)) != | |
513 STDERR_FILENO) { | |
514 ReportChildError(); | 507 ReportChildError(); |
515 } | 508 } |
516 | 509 |
517 // Report the final PID and do the exec. | 510 // Report the final PID and do the exec. |
518 ReportPid(getpid()); // getpid cannot fail. | 511 ReportPid(getpid()); // getpid cannot fail. |
519 VOID_TEMP_FAILURE_RETRY( | 512 VOID_TEMP_FAILURE_RETRY( |
520 execvp(path_, const_cast<char* const*>(program_arguments_))); | 513 execvp(path_, const_cast<char* const*>(program_arguments_))); |
521 ReportChildError(); | 514 ReportChildError(); |
522 } else { | 515 } else { |
523 // Exit the intermeiate process. | 516 // Exit the intermeiate process. |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
584 child_errno = result[1]; | 577 child_errno = result[1]; |
585 ReadChildError(); | 578 ReadChildError(); |
586 return child_errno; | 579 return child_errno; |
587 } else if (bytes_read == -1) { | 580 } else if (bytes_read == -1) { |
588 return errno; | 581 return errno; |
589 } | 582 } |
590 return 0; | 583 return 0; |
591 } | 584 } |
592 | 585 |
593 | 586 |
| 587 void SetupDetached() { |
| 588 ASSERT(mode_ == kDetached); |
| 589 |
| 590 // Close all open file descriptors except for exec_control_[1]. |
| 591 int max_fds = sysconf(_SC_OPEN_MAX); |
| 592 if (max_fds == -1) max_fds = _POSIX_OPEN_MAX; |
| 593 for (int fd = 0; fd < max_fds; fd++) { |
| 594 if (fd != exec_control_[1]) { |
| 595 VOID_TEMP_FAILURE_RETRY(close(fd)); |
| 596 } |
| 597 } |
| 598 |
| 599 // Re-open stdin, stdout and stderr and connect them to /dev/null. |
| 600 // The loop above should already have closed all of them, so |
| 601 // creating new file descriptors should start at STDIN_FILENO. |
| 602 int fd = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)); |
| 603 if (fd != STDIN_FILENO) { |
| 604 ReportChildError(); |
| 605 } |
| 606 if (TEMP_FAILURE_RETRY(dup2(STDIN_FILENO, STDOUT_FILENO)) != |
| 607 STDOUT_FILENO) { |
| 608 ReportChildError(); |
| 609 } |
| 610 if (TEMP_FAILURE_RETRY(dup2(STDIN_FILENO, STDERR_FILENO)) != |
| 611 STDERR_FILENO) { |
| 612 ReportChildError(); |
| 613 } |
| 614 } |
| 615 |
| 616 void SetupDetachedWithStdio() { |
| 617 // Close all open file descriptors except for |
| 618 // exec_control_[1], write_out_[0], read_in_[1] and |
| 619 // read_err_[1]. |
| 620 int max_fds = sysconf(_SC_OPEN_MAX); |
| 621 if (max_fds == -1) max_fds = _POSIX_OPEN_MAX; |
| 622 for (int fd = 0; fd < max_fds; fd++) { |
| 623 if (fd != exec_control_[1] && |
| 624 fd != write_out_[0] && |
| 625 fd != read_in_[1] && |
| 626 fd != read_err_[1]) { |
| 627 VOID_TEMP_FAILURE_RETRY(close(fd)); |
| 628 } |
| 629 } |
| 630 |
| 631 if (TEMP_FAILURE_RETRY(dup2(write_out_[0], STDIN_FILENO)) == -1) { |
| 632 ReportChildError(); |
| 633 } |
| 634 VOID_TEMP_FAILURE_RETRY(close(write_out_[0])); |
| 635 |
| 636 if (TEMP_FAILURE_RETRY(dup2(read_in_[1], STDOUT_FILENO)) == -1) { |
| 637 ReportChildError(); |
| 638 } |
| 639 VOID_TEMP_FAILURE_RETRY(close(read_in_[1])); |
| 640 |
| 641 if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) { |
| 642 ReportChildError(); |
| 643 } |
| 644 VOID_TEMP_FAILURE_RETRY(close(read_err_[1])); |
| 645 } |
| 646 |
| 647 |
594 int CleanupAndReturnError() { | 648 int CleanupAndReturnError() { |
595 int actual_errno = errno; | 649 int actual_errno = errno; |
596 // If CleanupAndReturnError is called without an actual errno make | 650 // If CleanupAndReturnError is called without an actual errno make |
597 // sure to return an error anyway. | 651 // sure to return an error anyway. |
598 if (actual_errno == 0) actual_errno = EPERM; | 652 if (actual_errno == 0) actual_errno = EPERM; |
599 SetChildOsErrorMessage(); | 653 SetChildOsErrorMessage(); |
600 CloseAllPipes(); | 654 CloseAllPipes(); |
601 return actual_errno; | 655 return actual_errno; |
602 } | 656 } |
603 | 657 |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
674 int read_in_[2]; // Pipe for stdout to child process. | 728 int read_in_[2]; // Pipe for stdout to child process. |
675 int read_err_[2]; // Pipe for stderr to child process. | 729 int read_err_[2]; // Pipe for stderr to child process. |
676 int write_out_[2]; // Pipe for stdin to child process. | 730 int write_out_[2]; // Pipe for stdin to child process. |
677 int exec_control_[2]; // Pipe to get the result from exec. | 731 int exec_control_[2]; // Pipe to get the result from exec. |
678 | 732 |
679 char** program_arguments_; | 733 char** program_arguments_; |
680 char** program_environment_; | 734 char** program_environment_; |
681 | 735 |
682 const char* path_; | 736 const char* path_; |
683 const char* working_directory_; | 737 const char* working_directory_; |
684 bool detach_; | 738 ProcessStartMode mode_; |
685 intptr_t* in_; | 739 intptr_t* in_; |
686 intptr_t* out_; | 740 intptr_t* out_; |
687 intptr_t* err_; | 741 intptr_t* err_; |
688 intptr_t* id_; | 742 intptr_t* id_; |
689 intptr_t* exit_event_; | 743 intptr_t* exit_event_; |
690 char** os_error_message_; | 744 char** os_error_message_; |
691 }; | 745 }; |
692 | 746 |
693 | 747 |
694 int Process::Start(const char* path, | 748 int Process::Start(const char* path, |
695 char* arguments[], | 749 char* arguments[], |
696 intptr_t arguments_length, | 750 intptr_t arguments_length, |
697 const char* working_directory, | 751 const char* working_directory, |
698 char* environment[], | 752 char* environment[], |
699 intptr_t environment_length, | 753 intptr_t environment_length, |
700 bool detach, | 754 ProcessStartMode mode, |
701 intptr_t* in, | 755 intptr_t* in, |
702 intptr_t* out, | 756 intptr_t* out, |
703 intptr_t* err, | 757 intptr_t* err, |
704 intptr_t* id, | 758 intptr_t* id, |
705 intptr_t* exit_event, | 759 intptr_t* exit_event, |
706 char** os_error_message) { | 760 char** os_error_message) { |
707 ProcessStarter starter(path, | 761 ProcessStarter starter(path, |
708 arguments, | 762 arguments, |
709 arguments_length, | 763 arguments_length, |
710 working_directory, | 764 working_directory, |
711 environment, | 765 environment, |
712 environment_length, | 766 environment_length, |
713 detach, | 767 mode, |
714 in, | 768 in, |
715 out, | 769 out, |
716 err, | 770 err, |
717 id, | 771 id, |
718 exit_event, | 772 exit_event, |
719 os_error_message); | 773 os_error_message); |
720 return starter.Start(); | 774 return starter.Start(); |
721 } | 775 } |
722 | 776 |
723 | 777 |
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
959 bzero(&act, sizeof(act)); | 1013 bzero(&act, sizeof(act)); |
960 act.sa_handler = SIG_DFL; | 1014 act.sa_handler = SIG_DFL; |
961 VOID_NO_RETRY_EXPECTED(sigaction(signal, &act, NULL)); | 1015 VOID_NO_RETRY_EXPECTED(sigaction(signal, &act, NULL)); |
962 } | 1016 } |
963 } | 1017 } |
964 | 1018 |
965 } // namespace bin | 1019 } // namespace bin |
966 } // namespace dart | 1020 } // namespace dart |
967 | 1021 |
968 #endif // defined(TARGET_OS_ANDROID) | 1022 #endif // defined(TARGET_OS_ANDROID) |
OLD | NEW |