Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(157)

Side by Side Diff: runtime/bin/process_android.cc

Issue 884143002: Refactor the process creation code on POSIX platforms (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fix Mac OS and Android buiæd Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/bin/process.cc ('k') | runtime/bin/process_linux.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 static Monitor* monitor_; 223 static Monitor* monitor_;
224 }; 224 };
225 225
226 226
227 bool ExitCodeHandler::running_ = false; 227 bool ExitCodeHandler::running_ = false;
228 int ExitCodeHandler::process_count_ = 0; 228 int ExitCodeHandler::process_count_ = 0;
229 bool ExitCodeHandler::terminate_done_ = false; 229 bool ExitCodeHandler::terminate_done_ = false;
230 Monitor* ExitCodeHandler::monitor_ = new Monitor(); 230 Monitor* ExitCodeHandler::monitor_ = new Monitor();
231 231
232 232
233 static void SetChildOsErrorMessage(char** os_error_message) { 233 class ProcessStarter {
234 const int kBufferSize = 1024; 234 public:
235 char error_message[kBufferSize]; 235 ProcessStarter(const char* path,
236 strerror_r(errno, error_message, kBufferSize); 236 char* arguments[],
237 *os_error_message = strdup(error_message); 237 intptr_t arguments_length,
238 } 238 const char* working_directory,
239 239 char* environment[],
240 240 intptr_t environment_length,
241 static void ReportChildError(int exec_control_fd) { 241 bool detach,
242 // In the case of failure in the child process write the errno and 242 intptr_t* in,
243 // the OS error message to the exec control pipe and exit. 243 intptr_t* out,
244 int child_errno = errno; 244 intptr_t* err,
245 const int kBufferSize = 1024; 245 intptr_t* id,
246 char os_error_message[kBufferSize]; 246 intptr_t* exit_event,
247 strerror_r(errno, os_error_message, kBufferSize); 247 char** os_error_message)
248 ASSERT(sizeof(child_errno) == sizeof(errno)); 248 : path_(path),
249 int bytes_written = 249 working_directory_(working_directory),
250 detach_(detach),
251 in_(in),
252 out_(out),
253 err_(err),
254 id_(id),
255 exit_event_(exit_event),
256 os_error_message_(os_error_message) {
257 read_in_[0] = -1;
258 read_in_[1] = -1;
259 read_err_[0] = -1;
260 read_err_[1] = -1;
261 write_out_[0] = -1;
262 write_out_[1] = -1;
263 exec_control_[0] = -1;
264 exec_control_[1] = -1;
265
266 program_arguments_ = new char*[arguments_length + 2];
267 program_arguments_[0] = const_cast<char*>(path_);
268 for (int i = 0; i < arguments_length; i++) {
269 program_arguments_[i + 1] = arguments[i];
270 }
271 program_arguments_[arguments_length + 1] = NULL;
272
273 program_environment_ = NULL;
274 if (environment != NULL) {
275 program_environment_ = new char*[environment_length + 1];
276 for (int i = 0; i < environment_length; i++) {
277 program_environment_[i] = environment[i];
278 }
279 program_environment_[environment_length] = NULL;
280 }
281 }
282
283
284 ~ProcessStarter() {
285 delete[] program_arguments_;
286 delete[] program_environment_;
287 }
288
289
290 int Start() {
291 // Create pipes required.
292 int err = CreatePipes();
293 if (err != 0) return err;
294
295 // Fork to create the new process.
296 pid_t pid = TEMP_FAILURE_RETRY(fork());
297 if (pid < 0) {
298 // Failed to fork.
299 return CleanupAndReturnError();
300 } else if (pid == 0) {
301 // This runs in the new process.
302 NewProcess();
303 }
304
305 // This runs in the original process.
306
307 // Be sure to listen for exit-codes, now we have a child-process.
308 ExitCodeHandler::ProcessStarted();
309
310 // Register the child process if not detached.
311 if (!detach_) {
312 err = RegisterProcess(pid);
313 if (err != 0) return err;
314 }
315
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
318 // exit code.
319 char msg = '1';
320 int bytes_written =
321 FDUtils::WriteToBlocking(read_in_[1], &msg, sizeof(msg));
322 if (bytes_written != sizeof(msg)) {
323 return CleanupAndReturnError();
324 }
325
326 // Read the result of executing the child process.
327 VOID_TEMP_FAILURE_RETRY(close(exec_control_[1]));
328 exec_control_[1] = -1;
329 if (!detach_) {
330 err = ReadExecResult();
331 } else {
332 err = ReadDetachedExecResult(&pid);
333 }
334 VOID_TEMP_FAILURE_RETRY(close(exec_control_[0]));
335 exec_control_[0] = -1;
336
337 // Return error code if any failures.
338 if (err != 0) {
339 if (!detach_) {
340 // Since exec() failed, we're not interested in the exit code.
341 // We close the reading side of the exit code pipe here.
342 // GetProcessExitCodes will get a broken pipe error when it
343 // tries to write to the writing side of the pipe and it will
344 // ignore the error.
345 VOID_TEMP_FAILURE_RETRY(close(*exit_event_));
346 *exit_event_ = -1;
347 }
348 CloseAllPipes();
349 return err;
350 }
351
352 if (!detach_) {
353 // Connect stdio, stdout and stderr.
354 FDUtils::SetNonBlocking(read_in_[0]);
355 *in_ = read_in_[0];
356 VOID_TEMP_FAILURE_RETRY(close(read_in_[1]));
357 FDUtils::SetNonBlocking(write_out_[1]);
358 *out_ = write_out_[1];
359 VOID_TEMP_FAILURE_RETRY(close(write_out_[0]));
360 FDUtils::SetNonBlocking(read_err_[0]);
361 *err_ = read_err_[0];
362 VOID_TEMP_FAILURE_RETRY(close(read_err_[1]));
363 } else {
364 // Close all fds.
365 VOID_TEMP_FAILURE_RETRY(close(read_in_[0]));
366 VOID_TEMP_FAILURE_RETRY(close(read_in_[1]));
367 ASSERT(write_out_[0] == -1);
368 ASSERT(write_out_[1] == -1);
369 ASSERT(read_err_[0] == -1);
370 ASSERT(read_err_[1] == -1);
371 }
372 ASSERT(exec_control_[0] == -1);
373 ASSERT(exec_control_[1] == -1);
374
375 *id_ = pid;
376 return 0;
377 }
378
379 private:
380 int CreatePipes() {
381 int result;
382 result = TEMP_FAILURE_RETRY(pipe(exec_control_));
383 if (result < 0) {
384 return CleanupAndReturnError();
385 }
386 FDUtils::SetCloseOnExec(exec_control_[0]);
387 FDUtils::SetCloseOnExec(exec_control_[1]);
388
389 // For a detached process the pipe to connect stdout is still used for
390 // signaling when to do the first fork.
391 result = TEMP_FAILURE_RETRY(pipe(read_in_));
392 if (result < 0) {
393 return CleanupAndReturnError();
394 }
395 FDUtils::SetCloseOnExec(read_in_[0]);
396
397 // For detached processes the pipe to connect stderr and stdin are not used.
398 if (!detach_) {
399 result = TEMP_FAILURE_RETRY(pipe(read_err_));
400 if (result < 0) {
401 return CleanupAndReturnError();
402 }
403 FDUtils::SetCloseOnExec(read_err_[0]);
404
405 result = TEMP_FAILURE_RETRY(pipe(write_out_));
406 if (result < 0) {
407 return CleanupAndReturnError();
408 }
409 FDUtils::SetCloseOnExec(write_out_[1]);
410 }
411
412 return 0;
413 }
414
415
416 void NewProcess() {
417 // Wait for parent process before setting up the child process.
418 char msg;
419 int bytes_read = FDUtils::ReadFromBlocking(read_in_[0], &msg, sizeof(msg));
420 if (bytes_read != sizeof(msg)) {
421 perror("Failed receiving notification message");
422 exit(1);
423 }
424 if (detach_) {
425 ExecDetachedProcess();
426 } else {
427 ExecProcess();
428 }
429 }
430
431
432 void ExecProcess() {
433 VOID_TEMP_FAILURE_RETRY(close(write_out_[1]));
434 VOID_TEMP_FAILURE_RETRY(close(read_in_[0]));
435 VOID_TEMP_FAILURE_RETRY(close(read_err_[0]));
436 VOID_TEMP_FAILURE_RETRY(close(exec_control_[0]));
437
438 if (TEMP_FAILURE_RETRY(dup2(write_out_[0], STDIN_FILENO)) == -1) {
439 ReportChildError();
440 }
441 VOID_TEMP_FAILURE_RETRY(close(write_out_[0]));
442
443 if (TEMP_FAILURE_RETRY(dup2(read_in_[1], STDOUT_FILENO)) == -1) {
444 ReportChildError();
445 }
446 VOID_TEMP_FAILURE_RETRY(close(read_in_[1]));
447
448 if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) {
449 ReportChildError();
450 }
451 VOID_TEMP_FAILURE_RETRY(close(read_err_[1]));
452
453 if (working_directory_ != NULL &&
454 TEMP_FAILURE_RETRY(chdir(working_directory_)) == -1) {
455 ReportChildError();
456 }
457
458 if (program_environment_ != NULL) {
459 environ = program_environment_;
460 }
461
462 VOID_TEMP_FAILURE_RETRY(
463 execvp(path_, const_cast<char* const*>(program_arguments_)));
464
465 ReportChildError();
466 }
467
468
469 void ExecDetachedProcess() {
470 ASSERT(write_out_[0] == -1);
471 ASSERT(write_out_[1] == -1);
472 ASSERT(read_err_[0] == -1);
473 ASSERT(read_err_[1] == -1);
474 // For a detached process the pipe to connect stdout is only used for
475 // signaling when to do the first fork.
476 VOID_TEMP_FAILURE_RETRY(close(read_in_[0]));
477 VOID_TEMP_FAILURE_RETRY(close(read_in_[1]));
478 // Fork once more to start a new session.
479 pid_t pid = TEMP_FAILURE_RETRY(fork());
480 if (pid < 0) {
481 ReportChildError();
482 } else if (pid == 0) {
483 // Start a new session.
484 if (TEMP_FAILURE_RETRY(setsid()) == -1) {
485 ReportChildError();
486 } else {
487 // Do a final fork to not be the session leader.
488 pid = TEMP_FAILURE_RETRY(fork());
489 if (pid < 0) {
490 ReportChildError();
491 } else if (pid == 0) {
492 // Close all open file descriptors except for exec_control_[1].
493 int max_fds = sysconf(_SC_OPEN_MAX);
494 if (max_fds == -1) max_fds = _POSIX_OPEN_MAX;
495 for (int fd = 0; fd < max_fds; fd++) {
496 if (fd != exec_control_[1]) {
497 VOID_TEMP_FAILURE_RETRY(close(fd));
498 }
499 }
500
501 // Re-open stdin, stdout and stderr and connect them to /dev/null.
502 // The loop above should already have closed all of them, so
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();
515 }
516
517 // Report the final PID and do the exec.
518 ReportPid(getpid()); // getpid cannot fail.
519 VOID_TEMP_FAILURE_RETRY(
520 execvp(path_, const_cast<char* const*>(program_arguments_)));
521 ReportChildError();
522 } else {
523 // Exit the intermeiate process.
524 exit(0);
525 }
526 }
527 } else {
528 // Exit the intermeiate process.
529 exit(0);
530 }
531 }
532
533
534 int RegisterProcess(pid_t pid) {
535 int result;
536 int event_fds[2];
537 result = TEMP_FAILURE_RETRY(pipe(event_fds));
538 if (result < 0) {
539 return CleanupAndReturnError();
540 }
541 FDUtils::SetCloseOnExec(event_fds[0]);
542 FDUtils::SetCloseOnExec(event_fds[1]);
543
544 ProcessInfoList::AddProcess(pid, event_fds[1]);
545 *exit_event_ = event_fds[0];
546 FDUtils::SetNonBlocking(event_fds[0]);
547 return 0;
548 }
549
550
551 int ReadExecResult() {
552 int child_errno;
553 int bytes_read = -1;
554 // Read exec result from child. If no data is returned the exec was
555 // successful and the exec call closed the pipe. Otherwise the errno
556 // is written to the pipe.
557 bytes_read =
558 FDUtils::ReadFromBlocking(
559 exec_control_[0], &child_errno, sizeof(child_errno));
560 if (bytes_read == sizeof(child_errno)) {
561 ReadChildError();
562 return child_errno;
563 } else if (bytes_read == -1) {
564 return errno;
565 }
566 return 0;
567 }
568
569
570 int ReadDetachedExecResult(pid_t *pid) {
571 int child_errno;
572 int bytes_read = -1;
573 // Read exec result from child. If only pid data is returned the exec was
574 // successful and the exec call closed the pipe. Otherwise the errno
575 // is written to the pipe as well.
576 int result[2];
577 bytes_read =
578 FDUtils::ReadFromBlocking(
579 exec_control_[0], result, sizeof(result));
580 if (bytes_read == sizeof(int)) {
581 *pid = result[0];
582 } else if (bytes_read == 2 * sizeof(int)) {
583 *pid = result[0];
584 child_errno = result[1];
585 ReadChildError();
586 return child_errno;
587 } else if (bytes_read == -1) {
588 return errno;
589 }
590 return 0;
591 }
592
593
594 int CleanupAndReturnError() {
595 int actual_errno = errno;
596 // If CleanupAndReturnError is called without an actual errno make
597 // sure to return an error anyway.
598 if (actual_errno == 0) actual_errno = EPERM;
599 SetChildOsErrorMessage();
600 CloseAllPipes();
601 return actual_errno;
602 }
603
604
605 void SetChildOsErrorMessage() {
606 const int kBufferSize = 1024;
607 char error_message[kBufferSize];
608 strerror_r(errno, error_message, kBufferSize);
609 *os_error_message_ = strdup(error_message);
610 }
611
612
613 void ReportChildError() {
614 // In the case of failure in the child process write the errno and
615 // the OS error message to the exec control pipe and exit.
616 int child_errno = errno;
617 const int kBufferSize = 1024;
618 char os_error_message[kBufferSize];
619 strerror_r(errno, os_error_message, kBufferSize);
620 int bytes_written =
621 FDUtils::WriteToBlocking(
622 exec_control_[1], &child_errno, sizeof(child_errno));
623 if (bytes_written == sizeof(child_errno)) {
250 FDUtils::WriteToBlocking( 624 FDUtils::WriteToBlocking(
251 exec_control_fd, &child_errno, sizeof(child_errno)); 625 exec_control_[1], os_error_message, strlen(os_error_message) + 1);
252 if (bytes_written == sizeof(child_errno)) { 626 }
253 FDUtils::WriteToBlocking( 627 VOID_TEMP_FAILURE_RETRY(close(exec_control_[1]));
254 exec_control_fd, os_error_message, strlen(os_error_message) + 1); 628 exit(1);
255 } 629 }
256 VOID_TEMP_FAILURE_RETRY(close(exec_control_fd)); 630
257 exit(1); 631
258 } 632 void ReportPid(int pid) {
259 633 // In the case of starting a detached process the actual pid of that process
260 634 // is communicated using the exec control pipe.
261 static void ReportPid(int exec_control_fd, int pid) { 635 int bytes_written =
262 // In the case of starting a detached process the actual pid of that process 636 FDUtils::WriteToBlocking(exec_control_[1], &pid, sizeof(pid));
263 // is communicated using the exec control pipe. 637 ASSERT(bytes_written == sizeof(int));
264 int bytes_written = 638 USE(bytes_written);
265 FDUtils::WriteToBlocking(exec_control_fd, &pid, sizeof(pid)); 639 }
266 ASSERT(bytes_written == sizeof(int)); 640
267 USE(bytes_written); 641
268 } 642 void ReadChildError() {
269 643 const int kMaxMessageSize = 256;
270 644 char* message = static_cast<char*>(malloc(kMaxMessageSize));
271 static void ReadChildError(int exec_control_fd, char** error_message) { 645 if (message != NULL) {
272 const int kMaxMessageSize = 256; 646 FDUtils::ReadFromBlocking(exec_control_[0], message, kMaxMessageSize);
273 char* message = static_cast<char*>(malloc(kMaxMessageSize)); 647 message[kMaxMessageSize - 1] = '\0';
274 if (message != NULL) { 648 *os_error_message_ = message;
275 FDUtils::ReadFromBlocking(exec_control_fd, message, kMaxMessageSize); 649 } else {
276 message[kMaxMessageSize - 1] = '\0'; 650 // Could not get error message. It will be NULL.
277 *error_message = message; 651 ASSERT(*os_error_message_ == NULL);
278 } else { 652 }
279 static const char* no_message = "Cannot get error message, out of memory"; 653 }
280 *error_message = const_cast<char*>(no_message); 654
281 } 655
282 } 656 void ClosePipe(int* fds) {
657 for (int i = 0; i < 2; i++) {
658 if (fds[i] != -1) {
659 VOID_TEMP_FAILURE_RETRY(close(fds[i]));
660 fds[i] = -1;
661 }
662 }
663 }
664
665
666 void CloseAllPipes() {
667 ClosePipe(exec_control_);
668 ClosePipe(read_in_);
669 ClosePipe(read_err_);
670 ClosePipe(write_out_);
671 }
672
673
674 int read_in_[2]; // Pipe for stdout to child process.
675 int read_err_[2]; // Pipe for stderr to child process.
676 int write_out_[2]; // Pipe for stdin to child process.
677 int exec_control_[2]; // Pipe to get the result from exec.
678
679 char** program_arguments_;
680 char** program_environment_;
681
682 const char* path_;
683 const char* working_directory_;
684 bool detach_;
685 intptr_t* in_;
686 intptr_t* out_;
687 intptr_t* err_;
688 intptr_t* id_;
689 intptr_t* exit_event_;
690 char** os_error_message_;
691 };
283 692
284 693
285 int Process::Start(const char* path, 694 int Process::Start(const char* path,
286 char* arguments[], 695 char* arguments[],
287 intptr_t arguments_length, 696 intptr_t arguments_length,
288 const char* working_directory, 697 const char* working_directory,
289 char* environment[], 698 char* environment[],
290 intptr_t environment_length, 699 intptr_t environment_length,
291 bool detach, 700 bool detach,
292 intptr_t* in, 701 intptr_t* in,
293 intptr_t* out, 702 intptr_t* out,
294 intptr_t* err, 703 intptr_t* err,
295 intptr_t* id, 704 intptr_t* id,
296 intptr_t* exit_event, 705 intptr_t* exit_event,
297 char** os_error_message) { 706 char** os_error_message) {
298 pid_t pid; 707 ProcessStarter starter(path,
299 int read_in[2] = {-1, -1}; // Pipe for stdout to child process. 708 arguments,
300 int read_err[2] = {-1, -1}; // Pipe for stderr to child process. 709 arguments_length,
301 int write_out[2] = {-1, -1}; // Pipe for stdin to child process. 710 working_directory,
302 int exec_control[2] = {-1, -1}; // Pipe to get the result from exec. 711 environment,
303 int result; 712 environment_length,
304 713 detach,
305 result = TEMP_FAILURE_RETRY(pipe(exec_control)); 714 in,
306 if (result < 0) { 715 out,
307 SetChildOsErrorMessage(os_error_message); 716 err,
308 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); 717 id,
309 return errno; 718 exit_event,
310 } 719 os_error_message);
311 FDUtils::SetCloseOnExec(exec_control[0]); 720 return starter.Start();
312 FDUtils::SetCloseOnExec(exec_control[1]);
313
314 // For a detached process the pipe to connect stdout is still used for
315 // signaling when to do the first fork.
316 result = TEMP_FAILURE_RETRY(pipe(read_in));
317 if (result < 0) {
318 SetChildOsErrorMessage(os_error_message);
319 VOID_TEMP_FAILURE_RETRY(close(exec_control[0]));
320 VOID_TEMP_FAILURE_RETRY(close(exec_control[1]));
321 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message);
322 return errno;
323 }
324 FDUtils::SetCloseOnExec(read_in[0]);
325
326 // For detached processes the pipe to connect stderr and stdin are not used.
327 if (!detach) {
328 result = TEMP_FAILURE_RETRY(pipe(read_err));
329 if (result < 0) {
330 SetChildOsErrorMessage(os_error_message);
331 VOID_TEMP_FAILURE_RETRY(close(exec_control[0]));
332 VOID_TEMP_FAILURE_RETRY(close(exec_control[1]));
333 VOID_TEMP_FAILURE_RETRY(close(read_in[0]));
334 VOID_TEMP_FAILURE_RETRY(close(read_in[1]));
335 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message);
336 return errno;
337 }
338 FDUtils::SetCloseOnExec(read_err[0]);
339
340 result = TEMP_FAILURE_RETRY(pipe(write_out));
341 if (result < 0) {
342 SetChildOsErrorMessage(os_error_message);
343 VOID_TEMP_FAILURE_RETRY(close(exec_control[0]));
344 VOID_TEMP_FAILURE_RETRY(close(exec_control[1]));
345 VOID_TEMP_FAILURE_RETRY(close(read_in[0]));
346 VOID_TEMP_FAILURE_RETRY(close(read_in[1]));
347 VOID_TEMP_FAILURE_RETRY(close(read_err[0]));
348 VOID_TEMP_FAILURE_RETRY(close(read_err[1]));
349 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message);
350 return errno;
351 }
352 FDUtils::SetCloseOnExec(write_out[1]);
353 }
354
355 char** program_arguments = new char*[arguments_length + 2];
356 program_arguments[0] = const_cast<char*>(path);
357 for (int i = 0; i < arguments_length; i++) {
358 program_arguments[i + 1] = arguments[i];
359 }
360 program_arguments[arguments_length + 1] = NULL;
361
362 char** program_environment = NULL;
363 if (environment != NULL) {
364 program_environment = new char*[environment_length + 1];
365 for (int i = 0; i < environment_length; i++) {
366 program_environment[i] = environment[i];
367 }
368 program_environment[environment_length] = NULL;
369 }
370
371 pid = TEMP_FAILURE_RETRY(fork());
372 if (pid < 0) {
373 SetChildOsErrorMessage(os_error_message);
374 delete[] program_arguments;
375 VOID_TEMP_FAILURE_RETRY(close(exec_control[0]));
376 VOID_TEMP_FAILURE_RETRY(close(exec_control[1]));
377 VOID_TEMP_FAILURE_RETRY(close(read_in[0]));
378 VOID_TEMP_FAILURE_RETRY(close(read_in[1]));
379 if (!detach) {
380 VOID_TEMP_FAILURE_RETRY(close(read_err[0]));
381 VOID_TEMP_FAILURE_RETRY(close(read_err[1]));
382 VOID_TEMP_FAILURE_RETRY(close(write_out[0]));
383 VOID_TEMP_FAILURE_RETRY(close(write_out[1]));
384 }
385 return errno;
386 } else if (pid == 0) {
387 // Wait for parent process before setting up the child process.
388 char msg;
389 int bytes_read = FDUtils::ReadFromBlocking(read_in[0], &msg, sizeof(msg));
390 if (bytes_read != sizeof(msg)) {
391 perror("Failed receiving notification message");
392 exit(1);
393 }
394 if (detach) {
395 // For a detached process the pipe to connect stdout is only used for
396 // signaling when to do the first fork.
397 VOID_TEMP_FAILURE_RETRY(close(read_in[0]));
398 VOID_TEMP_FAILURE_RETRY(close(read_in[1]));
399 // Fork once more to start a new session.
400 pid = TEMP_FAILURE_RETRY(fork());
401 if (pid < 0) {
402 ReportChildError(exec_control[1]);
403 } else if (pid == 0) {
404 // Start a new session.
405 if (TEMP_FAILURE_RETRY(setsid()) == -1) {
406 ReportChildError(exec_control[1]);
407 } else {
408 // Do a final fork to not be the session leader.
409 pid = TEMP_FAILURE_RETRY(fork());
410 if (pid < 0) {
411 ReportChildError(exec_control[1]);
412 } else if (pid == 0) {
413 // Close all open file descriptors except for exec_control[1].
414 int max_fds = sysconf(_SC_OPEN_MAX);
415 if (max_fds == -1) max_fds = _POSIX_OPEN_MAX;
416 for (int fd = 0; fd < max_fds; fd++) {
417 if (fd != exec_control[1]) {
418 VOID_TEMP_FAILURE_RETRY(close(fd));
419 }
420 }
421
422 // Re-open stdin, stdout and stderr and connect them to /dev/null.
423 // The loop above should already have closed all of them, so
424 // creating new file descriptors should start at STDIN_FILENO.
425 int fd = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
426 if (fd != STDIN_FILENO) {
427 ReportChildError(exec_control[1]);
428 }
429 if (TEMP_FAILURE_RETRY(dup2(STDIN_FILENO, STDOUT_FILENO)) !=
430 STDOUT_FILENO) {
431 ReportChildError(exec_control[1]);
432 }
433 if (TEMP_FAILURE_RETRY(dup2(STDIN_FILENO, STDERR_FILENO)) !=
434 STDERR_FILENO) {
435 ReportChildError(exec_control[1]);
436 }
437
438 // Report the final PID and do the exec.
439 ReportPid(exec_control[1], getpid()); // getpid cannot fail.
440 VOID_TEMP_FAILURE_RETRY(
441 execvp(path, const_cast<char* const*>(program_arguments)));
442 ReportChildError(exec_control[1]);
443 } else {
444 exit(0);
445 }
446 }
447 } else {
448 exit(0);
449 }
450 } else {
451 VOID_TEMP_FAILURE_RETRY(close(write_out[1]));
452 VOID_TEMP_FAILURE_RETRY(close(read_in[0]));
453 VOID_TEMP_FAILURE_RETRY(close(read_err[0]));
454 VOID_TEMP_FAILURE_RETRY(close(exec_control[0]));
455
456 if (TEMP_FAILURE_RETRY(dup2(write_out[0], STDIN_FILENO)) == -1) {
457 ReportChildError(exec_control[1]);
458 }
459 VOID_TEMP_FAILURE_RETRY(close(write_out[0]));
460
461 if (TEMP_FAILURE_RETRY(dup2(read_in[1], STDOUT_FILENO)) == -1) {
462 ReportChildError(exec_control[1]);
463 }
464 VOID_TEMP_FAILURE_RETRY(close(read_in[1]));
465
466 if (TEMP_FAILURE_RETRY(dup2(read_err[1], STDERR_FILENO)) == -1) {
467 ReportChildError(exec_control[1]);
468 }
469 VOID_TEMP_FAILURE_RETRY(close(read_err[1]));
470
471 if (working_directory != NULL &&
472 TEMP_FAILURE_RETRY(chdir(working_directory)) == -1) {
473 ReportChildError(exec_control[1]);
474 }
475
476 if (program_environment != NULL) {
477 environ = program_environment;
478 }
479
480 VOID_TEMP_FAILURE_RETRY(
481 execvp(path, const_cast<char* const*>(program_arguments)));
482
483 ReportChildError(exec_control[1]);
484 }
485 }
486
487 // Be sure to listen for exit-codes, now we have a child-process.
488 ExitCodeHandler::ProcessStarted();
489
490 // The arguments and environment for the spawned process are not needed
491 // any longer.
492 delete[] program_arguments;
493 delete[] program_environment;
494
495 if (!detach) {
496 int event_fds[2];
497 result = TEMP_FAILURE_RETRY(pipe(event_fds));
498 if (result < 0) {
499 SetChildOsErrorMessage(os_error_message);
500 VOID_TEMP_FAILURE_RETRY(close(read_in[0]));
501 VOID_TEMP_FAILURE_RETRY(close(read_in[1]));
502 VOID_TEMP_FAILURE_RETRY(close(read_err[0]));
503 VOID_TEMP_FAILURE_RETRY(close(read_err[1]));
504 VOID_TEMP_FAILURE_RETRY(close(write_out[0]));
505 VOID_TEMP_FAILURE_RETRY(close(write_out[1]));
506 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message);
507 return errno;
508 }
509 FDUtils::SetCloseOnExec(event_fds[0]);
510 FDUtils::SetCloseOnExec(event_fds[1]);
511
512 ProcessInfoList::AddProcess(pid, event_fds[1]);
513 *exit_event = event_fds[0];
514 FDUtils::SetNonBlocking(event_fds[0]);
515 }
516
517 // Notify child process to start.
518 char msg = '1';
519 result = FDUtils::WriteToBlocking(read_in[1], &msg, sizeof(msg));
520 if (result != sizeof(msg)) {
521 perror("Failed sending notification message");
522 }
523
524 VOID_TEMP_FAILURE_RETRY(close(exec_control[1]));
525 bool failed = false;
526 int child_errno;
527 int bytes_read = -1;
528 ASSERT(sizeof(child_errno) == sizeof(errno));
529 if (!detach) {
530 // Read exec result from child. If no data is returned the exec was
531 // successful and the exec call closed the pipe. Otherwise the errno
532 // is written to the pipe.
533 bytes_read =
534 FDUtils::ReadFromBlocking(
535 exec_control[0], &child_errno, sizeof(child_errno));
536 if (bytes_read == sizeof(child_errno)) {
537 ReadChildError(exec_control[0], os_error_message);
538 failed = true;
539 }
540 } else {
541 // Read exec result from child. If only pid data is returned the exec was
542 // successful and the exec call closed the pipe. Otherwise the errno
543 // is written to the pipe as well.
544 int result[2];
545 ASSERT(sizeof(int) == sizeof(child_errno));
546 bytes_read =
547 FDUtils::ReadFromBlocking(
548 exec_control[0], result, sizeof(result));
549 if (bytes_read == sizeof(int)) {
550 pid = result[0];
551 } else if (bytes_read == 2 * sizeof(int)) {
552 pid = result[0];
553 child_errno = result[1];
554 ReadChildError(exec_control[0], os_error_message);
555 failed = true;
556 }
557 }
558 VOID_TEMP_FAILURE_RETRY(close(exec_control[0]));
559
560 // Return error code if any failures.
561 if (failed) {
562 if (!detach) {
563 VOID_TEMP_FAILURE_RETRY(close(read_in[0]));
564 VOID_TEMP_FAILURE_RETRY(close(read_in[1]));
565 VOID_TEMP_FAILURE_RETRY(close(read_err[0]));
566 VOID_TEMP_FAILURE_RETRY(close(read_err[1]));
567 VOID_TEMP_FAILURE_RETRY(close(write_out[0]));
568 VOID_TEMP_FAILURE_RETRY(close(write_out[1]));
569
570 // Since exec() failed, we're not interested in the exit code.
571 // We close the reading side of the exit code pipe here.
572 // GetProcessExitCodes will get a broken pipe error when it tries to write
573 // to the writing side of the pipe and it will ignore the error.
574 VOID_TEMP_FAILURE_RETRY(close(*exit_event));
575 *exit_event = -1;
576 }
577 if (bytes_read == -1) {
578 return errno; // Read failed.
579 } else {
580 return child_errno; // Exec failed.
581 }
582 }
583
584 FDUtils::SetNonBlocking(read_in[0]);
585 *in = read_in[0];
586 VOID_TEMP_FAILURE_RETRY(close(read_in[1]));
587 FDUtils::SetNonBlocking(write_out[1]);
588 *out = write_out[1];
589 VOID_TEMP_FAILURE_RETRY(close(write_out[0]));
590 FDUtils::SetNonBlocking(read_err[0]);
591 *err = read_err[0];
592 VOID_TEMP_FAILURE_RETRY(close(read_err[1]));
593
594 *id = pid;
595 return 0;
596 } 721 }
597 722
598 723
599 class BufferList: public BufferListBase { 724 class BufferList: public BufferListBase {
600 public: 725 public:
601 bool Read(int fd, intptr_t available) { 726 bool Read(int fd, intptr_t available) {
602 // Read all available bytes. 727 // Read all available bytes.
603 while (available > 0) { 728 while (available > 0) {
604 if (free_size_ == 0) Allocate(); 729 if (free_size_ == 0) Allocate();
605 ASSERT(free_size_ > 0); 730 ASSERT(free_size_ > 0);
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
834 bzero(&act, sizeof(act)); 959 bzero(&act, sizeof(act));
835 act.sa_handler = SIG_DFL; 960 act.sa_handler = SIG_DFL;
836 VOID_NO_RETRY_EXPECTED(sigaction(signal, &act, NULL)); 961 VOID_NO_RETRY_EXPECTED(sigaction(signal, &act, NULL));
837 } 962 }
838 } 963 }
839 964
840 } // namespace bin 965 } // namespace bin
841 } // namespace dart 966 } // namespace dart
842 967
843 #endif // defined(TARGET_OS_ANDROID) 968 #endif // defined(TARGET_OS_ANDROID)
OLDNEW
« no previous file with comments | « runtime/bin/process.cc ('k') | runtime/bin/process_linux.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698