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

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

Powered by Google App Engine
This is Rietveld 408576698