| 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_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 |
| 11 #include <fcntl.h> // NOLINT | 11 #include <fcntl.h> // NOLINT |
| 12 #include <poll.h> // NOLINT | 12 #include <poll.h> // NOLINT |
| 13 #include <stdio.h> // NOLINT | 13 #include <stdio.h> // NOLINT |
| 14 #include <stdlib.h> // NOLINT | 14 #include <stdlib.h> // NOLINT |
| 15 #include <string.h> // NOLINT | 15 #include <string.h> // NOLINT |
| 16 #include <sys/wait.h> // NOLINT | 16 #include <sys/wait.h> // NOLINT |
| 17 #include <unistd.h> // NOLINT | 17 #include <unistd.h> // NOLINT |
| 18 | 18 |
| 19 #include "platform/signal_blocker.h" |
| 19 #include "bin/fdutils.h" | 20 #include "bin/fdutils.h" |
| 20 #include "bin/log.h" | 21 #include "bin/log.h" |
| 21 #include "bin/signal_blocker.h" | |
| 22 #include "bin/thread.h" | 22 #include "bin/thread.h" |
| 23 | 23 |
| 24 | 24 |
| 25 extern char **environ; | 25 extern char **environ; |
| 26 | 26 |
| 27 | 27 |
| 28 namespace dart { | 28 namespace dart { |
| 29 namespace bin { | 29 namespace bin { |
| 30 | 30 |
| 31 // ProcessInfo is used to map a process id to the file descriptor for | 31 // ProcessInfo is used to map a process id to the file descriptor for |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 144 | 144 |
| 145 if (!running_) { | 145 if (!running_) { |
| 146 return; | 146 return; |
| 147 } | 147 } |
| 148 | 148 |
| 149 // Set terminate_done_ to false, so we can use it as a guard for our | 149 // Set terminate_done_ to false, so we can use it as a guard for our |
| 150 // monitor. | 150 // monitor. |
| 151 running_ = false; | 151 running_ = false; |
| 152 | 152 |
| 153 // Fork to wake up waitpid. | 153 // Fork to wake up waitpid. |
| 154 if (TEMP_FAILURE_RETRY(fork()) == 0) { | 154 if (fork() == 0) { |
| 155 exit(0); | 155 exit(0); |
| 156 } | 156 } |
| 157 | 157 |
| 158 monitor_->Notify(); | 158 monitor_->Notify(); |
| 159 | 159 |
| 160 while (!terminate_done_) { | 160 while (!terminate_done_) { |
| 161 monitor_->Wait(dart::Monitor::kNoTimeout); | 161 monitor_->Wait(dart::Monitor::kNoTimeout); |
| 162 } | 162 } |
| 163 } | 163 } |
| 164 | 164 |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 267 intptr_t* id, | 267 intptr_t* id, |
| 268 intptr_t* exit_event, | 268 intptr_t* exit_event, |
| 269 char** os_error_message) { | 269 char** os_error_message) { |
| 270 pid_t pid; | 270 pid_t pid; |
| 271 int read_in[2]; // Pipe for stdout to child process. | 271 int read_in[2]; // Pipe for stdout to child process. |
| 272 int read_err[2]; // Pipe for stderr to child process. | 272 int read_err[2]; // Pipe for stderr to child process. |
| 273 int write_out[2]; // Pipe for stdin to child process. | 273 int write_out[2]; // Pipe for stdin to child process. |
| 274 int exec_control[2]; // Pipe to get the result from exec. | 274 int exec_control[2]; // Pipe to get the result from exec. |
| 275 int result; | 275 int result; |
| 276 | 276 |
| 277 result = TEMP_FAILURE_RETRY(pipe(read_in)); | 277 result = pipe(read_in); |
| 278 if (result < 0) { | 278 if (result < 0) { |
| 279 SetChildOsErrorMessage(os_error_message); | 279 SetChildOsErrorMessage(os_error_message); |
| 280 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); | 280 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); |
| 281 return errno; | 281 return errno; |
| 282 } | 282 } |
| 283 FDUtils::SetCloseOnExec(read_in[0]); | 283 FDUtils::SetCloseOnExec(read_in[0]); |
| 284 | 284 |
| 285 result = TEMP_FAILURE_RETRY(pipe(read_err)); | 285 result = pipe(read_err); |
| 286 if (result < 0) { | 286 if (result < 0) { |
| 287 SetChildOsErrorMessage(os_error_message); | 287 SetChildOsErrorMessage(os_error_message); |
| 288 TEMP_FAILURE_RETRY(close(read_in[0])); | 288 TEMP_FAILURE_RETRY(close(read_in[0])); |
| 289 TEMP_FAILURE_RETRY(close(read_in[1])); | 289 TEMP_FAILURE_RETRY(close(read_in[1])); |
| 290 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); | 290 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); |
| 291 return errno; | 291 return errno; |
| 292 } | 292 } |
| 293 FDUtils::SetCloseOnExec(read_err[0]); | 293 FDUtils::SetCloseOnExec(read_err[0]); |
| 294 | 294 |
| 295 result = TEMP_FAILURE_RETRY(pipe(write_out)); | 295 result = pipe(write_out); |
| 296 if (result < 0) { | 296 if (result < 0) { |
| 297 SetChildOsErrorMessage(os_error_message); | 297 SetChildOsErrorMessage(os_error_message); |
| 298 TEMP_FAILURE_RETRY(close(read_in[0])); | 298 TEMP_FAILURE_RETRY(close(read_in[0])); |
| 299 TEMP_FAILURE_RETRY(close(read_in[1])); | 299 TEMP_FAILURE_RETRY(close(read_in[1])); |
| 300 TEMP_FAILURE_RETRY(close(read_err[0])); | 300 TEMP_FAILURE_RETRY(close(read_err[0])); |
| 301 TEMP_FAILURE_RETRY(close(read_err[1])); | 301 TEMP_FAILURE_RETRY(close(read_err[1])); |
| 302 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); | 302 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); |
| 303 return errno; | 303 return errno; |
| 304 } | 304 } |
| 305 FDUtils::SetCloseOnExec(write_out[1]); | 305 FDUtils::SetCloseOnExec(write_out[1]); |
| 306 | 306 |
| 307 result = TEMP_FAILURE_RETRY(pipe(exec_control)); | 307 result = pipe(exec_control); |
| 308 if (result < 0) { | 308 if (result < 0) { |
| 309 SetChildOsErrorMessage(os_error_message); | 309 SetChildOsErrorMessage(os_error_message); |
| 310 TEMP_FAILURE_RETRY(close(read_in[0])); | 310 TEMP_FAILURE_RETRY(close(read_in[0])); |
| 311 TEMP_FAILURE_RETRY(close(read_in[1])); | 311 TEMP_FAILURE_RETRY(close(read_in[1])); |
| 312 TEMP_FAILURE_RETRY(close(read_err[0])); | 312 TEMP_FAILURE_RETRY(close(read_err[0])); |
| 313 TEMP_FAILURE_RETRY(close(read_err[1])); | 313 TEMP_FAILURE_RETRY(close(read_err[1])); |
| 314 TEMP_FAILURE_RETRY(close(write_out[0])); | 314 TEMP_FAILURE_RETRY(close(write_out[0])); |
| 315 TEMP_FAILURE_RETRY(close(write_out[1])); | 315 TEMP_FAILURE_RETRY(close(write_out[1])); |
| 316 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); | 316 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); |
| 317 return errno; | 317 return errno; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 342 | 342 |
| 343 char** program_environment = NULL; | 343 char** program_environment = NULL; |
| 344 if (environment != NULL) { | 344 if (environment != NULL) { |
| 345 program_environment = new char*[environment_length + 1]; | 345 program_environment = new char*[environment_length + 1]; |
| 346 for (int i = 0; i < environment_length; i++) { | 346 for (int i = 0; i < environment_length; i++) { |
| 347 program_environment[i] = environment[i]; | 347 program_environment[i] = environment[i]; |
| 348 } | 348 } |
| 349 program_environment[environment_length] = NULL; | 349 program_environment[environment_length] = NULL; |
| 350 } | 350 } |
| 351 | 351 |
| 352 pid = TEMP_FAILURE_RETRY(fork()); | 352 pid = fork(); |
| 353 if (pid < 0) { | 353 if (pid < 0) { |
| 354 SetChildOsErrorMessage(os_error_message); | 354 SetChildOsErrorMessage(os_error_message); |
| 355 delete[] program_arguments; | 355 delete[] program_arguments; |
| 356 TEMP_FAILURE_RETRY(close(read_in[0])); | 356 TEMP_FAILURE_RETRY(close(read_in[0])); |
| 357 TEMP_FAILURE_RETRY(close(read_in[1])); | 357 TEMP_FAILURE_RETRY(close(read_in[1])); |
| 358 TEMP_FAILURE_RETRY(close(read_err[0])); | 358 TEMP_FAILURE_RETRY(close(read_err[0])); |
| 359 TEMP_FAILURE_RETRY(close(read_err[1])); | 359 TEMP_FAILURE_RETRY(close(read_err[1])); |
| 360 TEMP_FAILURE_RETRY(close(write_out[0])); | 360 TEMP_FAILURE_RETRY(close(write_out[0])); |
| 361 TEMP_FAILURE_RETRY(close(write_out[1])); | 361 TEMP_FAILURE_RETRY(close(write_out[1])); |
| 362 TEMP_FAILURE_RETRY(close(exec_control[0])); | 362 TEMP_FAILURE_RETRY(close(exec_control[0])); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 384 if (TEMP_FAILURE_RETRY(dup2(read_in[1], STDOUT_FILENO)) == -1) { | 384 if (TEMP_FAILURE_RETRY(dup2(read_in[1], STDOUT_FILENO)) == -1) { |
| 385 ReportChildError(exec_control[1]); | 385 ReportChildError(exec_control[1]); |
| 386 } | 386 } |
| 387 TEMP_FAILURE_RETRY(close(read_in[1])); | 387 TEMP_FAILURE_RETRY(close(read_in[1])); |
| 388 | 388 |
| 389 if (TEMP_FAILURE_RETRY(dup2(read_err[1], STDERR_FILENO)) == -1) { | 389 if (TEMP_FAILURE_RETRY(dup2(read_err[1], STDERR_FILENO)) == -1) { |
| 390 ReportChildError(exec_control[1]); | 390 ReportChildError(exec_control[1]); |
| 391 } | 391 } |
| 392 TEMP_FAILURE_RETRY(close(read_err[1])); | 392 TEMP_FAILURE_RETRY(close(read_err[1])); |
| 393 | 393 |
| 394 if (working_directory != NULL && | 394 if (working_directory != NULL && chdir(working_directory) == -1) { |
| 395 TEMP_FAILURE_RETRY(chdir(working_directory)) == -1) { | |
| 396 ReportChildError(exec_control[1]); | 395 ReportChildError(exec_control[1]); |
| 397 } | 396 } |
| 398 | 397 |
| 399 if (program_environment != NULL) { | 398 if (program_environment != NULL) { |
| 400 environ = program_environment; | 399 environ = program_environment; |
| 401 } | 400 } |
| 402 | 401 |
| 403 TEMP_FAILURE_RETRY( | 402 execvp(path, const_cast<char* const*>(program_arguments)); |
| 404 execvp(path, const_cast<char* const*>(program_arguments))); | |
| 405 | 403 |
| 406 ReportChildError(exec_control[1]); | 404 ReportChildError(exec_control[1]); |
| 407 } | 405 } |
| 408 | 406 |
| 409 // Be sure to listen for exit-codes, now we have a child-process. | 407 // Be sure to listen for exit-codes, now we have a child-process. |
| 410 ExitCodeHandler::ProcessStarted(); | 408 ExitCodeHandler::ProcessStarted(); |
| 411 | 409 |
| 412 // The arguments and environment for the spawned process are not needed | 410 // The arguments and environment for the spawned process are not needed |
| 413 // any longer. | 411 // any longer. |
| 414 delete[] program_arguments; | 412 delete[] program_arguments; |
| 415 delete[] program_environment; | 413 delete[] program_environment; |
| 416 | 414 |
| 417 int event_fds[2]; | 415 int event_fds[2]; |
| 418 result = TEMP_FAILURE_RETRY(pipe(event_fds)); | 416 result = pipe(event_fds); |
| 419 if (result < 0) { | 417 if (result < 0) { |
| 420 SetChildOsErrorMessage(os_error_message); | 418 SetChildOsErrorMessage(os_error_message); |
| 421 TEMP_FAILURE_RETRY(close(read_in[0])); | 419 TEMP_FAILURE_RETRY(close(read_in[0])); |
| 422 TEMP_FAILURE_RETRY(close(read_in[1])); | 420 TEMP_FAILURE_RETRY(close(read_in[1])); |
| 423 TEMP_FAILURE_RETRY(close(read_err[0])); | 421 TEMP_FAILURE_RETRY(close(read_err[0])); |
| 424 TEMP_FAILURE_RETRY(close(read_err[1])); | 422 TEMP_FAILURE_RETRY(close(read_err[1])); |
| 425 TEMP_FAILURE_RETRY(close(write_out[0])); | 423 TEMP_FAILURE_RETRY(close(write_out[0])); |
| 426 TEMP_FAILURE_RETRY(close(write_out[1])); | 424 TEMP_FAILURE_RETRY(close(write_out[1])); |
| 427 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); | 425 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); |
| 428 return errno; | 426 return errno; |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 611 intptr_t exit_code = exit_code_data.ints[0]; | 609 intptr_t exit_code = exit_code_data.ints[0]; |
| 612 intptr_t negative = exit_code_data.ints[1]; | 610 intptr_t negative = exit_code_data.ints[1]; |
| 613 if (negative) exit_code = -exit_code; | 611 if (negative) exit_code = -exit_code; |
| 614 result->set_exit_code(exit_code); | 612 result->set_exit_code(exit_code); |
| 615 | 613 |
| 616 return true; | 614 return true; |
| 617 } | 615 } |
| 618 | 616 |
| 619 | 617 |
| 620 bool Process::Kill(intptr_t id, int signal) { | 618 bool Process::Kill(intptr_t id, int signal) { |
| 621 return (TEMP_FAILURE_RETRY(kill(id, signal)) != -1); | 619 return kill(id, signal) != -1; |
| 622 } | 620 } |
| 623 | 621 |
| 624 | 622 |
| 625 void Process::TerminateExitCodeHandler() { | 623 void Process::TerminateExitCodeHandler() { |
| 626 ExitCodeHandler::TerminateExitCodeThread(); | 624 ExitCodeHandler::TerminateExitCodeThread(); |
| 627 } | 625 } |
| 628 | 626 |
| 629 | 627 |
| 630 intptr_t Process::CurrentProcessId() { | 628 intptr_t Process::CurrentProcessId() { |
| 631 return static_cast<intptr_t>(getpid()); | 629 return static_cast<intptr_t>(getpid()); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 666 intptr_t Process::SetSignalHandler(intptr_t signal) { | 664 intptr_t Process::SetSignalHandler(intptr_t signal) { |
| 667 bool found = false; | 665 bool found = false; |
| 668 for (int i = 0; i < kSignalsCount; i++) { | 666 for (int i = 0; i < kSignalsCount; i++) { |
| 669 if (kSignals[i] == signal) { | 667 if (kSignals[i] == signal) { |
| 670 found = true; | 668 found = true; |
| 671 break; | 669 break; |
| 672 } | 670 } |
| 673 } | 671 } |
| 674 if (!found) return -1; | 672 if (!found) return -1; |
| 675 int fds[2]; | 673 int fds[2]; |
| 676 if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(pipe(fds)) != 0) { | 674 if (pipe(fds) != 0) { |
| 677 return -1; | 675 return -1; |
| 678 } | 676 } |
| 679 if (!FDUtils::SetNonBlocking(fds[0])) { | 677 if (!FDUtils::SetNonBlocking(fds[0])) { |
| 680 VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fds[0])); | 678 VOID_TEMP_FAILURE_RETRY(close(fds[0])); |
| 681 VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fds[1])); | 679 VOID_TEMP_FAILURE_RETRY(close(fds[1])); |
| 682 return -1; | 680 return -1; |
| 683 } | 681 } |
| 684 ThreadSignalBlocker blocker(kSignalsCount, kSignals); | 682 ThreadSignalBlocker blocker(kSignalsCount, kSignals); |
| 685 MutexLocker lock(signal_mutex); | 683 MutexLocker lock(signal_mutex); |
| 686 SignalInfo* handler = signal_handlers; | 684 SignalInfo* handler = signal_handlers; |
| 687 bool listen = true; | 685 bool listen = true; |
| 688 while (handler != NULL) { | 686 while (handler != NULL) { |
| 689 if (handler->signal() == signal) { | 687 if (handler->signal() == signal) { |
| 690 listen = false; | 688 listen = false; |
| 691 break; | 689 break; |
| 692 } | 690 } |
| 693 handler = handler->next(); | 691 handler = handler->next(); |
| 694 } | 692 } |
| 695 if (listen) { | 693 if (listen) { |
| 696 struct sigaction act; | 694 struct sigaction act; |
| 697 bzero(&act, sizeof(act)); | 695 bzero(&act, sizeof(act)); |
| 698 act.sa_handler = SignalHandler; | 696 act.sa_handler = SignalHandler; |
| 699 sigemptyset(&act.sa_mask); | 697 sigemptyset(&act.sa_mask); |
| 700 for (int i = 0; i < kSignalsCount; i++) { | 698 for (int i = 0; i < kSignalsCount; i++) { |
| 701 sigaddset(&act.sa_mask, kSignals[i]); | 699 sigaddset(&act.sa_mask, kSignals[i]); |
| 702 } | 700 } |
| 703 int status = TEMP_FAILURE_RETRY_BLOCK_SIGNALS( | 701 int status = sigaction(signal, &act, NULL); |
| 704 sigaction(signal, &act, NULL)); | |
| 705 if (status < 0) { | 702 if (status < 0) { |
| 706 VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fds[0])); | 703 VOID_TEMP_FAILURE_RETRY(close(fds[0])); |
| 707 VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fds[1])); | 704 VOID_TEMP_FAILURE_RETRY(close(fds[1])); |
| 708 return -1; | 705 return -1; |
| 709 } | 706 } |
| 710 } | 707 } |
| 711 if (signal_handlers == NULL) { | 708 if (signal_handlers == NULL) { |
| 712 signal_handlers = new SignalInfo(fds[1], signal); | 709 signal_handlers = new SignalInfo(fds[1], signal); |
| 713 } else { | 710 } else { |
| 714 new SignalInfo(fds[1], signal, signal_handlers); | 711 new SignalInfo(fds[1], signal, signal_handlers); |
| 715 } | 712 } |
| 716 return fds[0]; | 713 return fds[0]; |
| 717 } | 714 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 734 } | 731 } |
| 735 } | 732 } |
| 736 SignalInfo* next = handler->next(); | 733 SignalInfo* next = handler->next(); |
| 737 if (remove) delete handler; | 734 if (remove) delete handler; |
| 738 handler = next; | 735 handler = next; |
| 739 } | 736 } |
| 740 if (unlisten) { | 737 if (unlisten) { |
| 741 struct sigaction act; | 738 struct sigaction act; |
| 742 bzero(&act, sizeof(act)); | 739 bzero(&act, sizeof(act)); |
| 743 act.sa_handler = SIG_DFL; | 740 act.sa_handler = SIG_DFL; |
| 744 VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(sigaction(signal, &act, NULL)); | 741 sigaction(signal, &act, NULL); |
| 745 } | 742 } |
| 746 } | 743 } |
| 747 | 744 |
| 748 } // namespace bin | 745 } // namespace bin |
| 749 } // namespace dart | 746 } // namespace dart |
| 750 | 747 |
| 751 #endif // defined(TARGET_OS_LINUX) | 748 #endif // defined(TARGET_OS_LINUX) |
| OLD | NEW |