| 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 "bin/process.h" | 5 #include "bin/process.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <fcntl.h> | 8 #include <fcntl.h> |
| 9 #include <poll.h> | 9 #include <poll.h> |
| 10 #include <signal.h> | 10 #include <signal.h> |
| (...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 251 }; | 251 }; |
| 252 | 252 |
| 253 | 253 |
| 254 dart::Mutex ExitCodeHandler::mutex_; | 254 dart::Mutex ExitCodeHandler::mutex_; |
| 255 bool ExitCodeHandler::initialized_ = false; | 255 bool ExitCodeHandler::initialized_ = false; |
| 256 int ExitCodeHandler::sig_chld_fds_[2] = { 0, 0 }; | 256 int ExitCodeHandler::sig_chld_fds_[2] = { 0, 0 }; |
| 257 bool ExitCodeHandler::thread_terminated_ = false; | 257 bool ExitCodeHandler::thread_terminated_ = false; |
| 258 dart::Monitor ExitCodeHandler::thread_terminate_monitor_; | 258 dart::Monitor ExitCodeHandler::thread_terminate_monitor_; |
| 259 | 259 |
| 260 | 260 |
| 261 static char* SafeStrNCpy(char* dest, const char* src, size_t n) { | 261 static void SetChildOsErrorMessage(char** os_error_message) { |
| 262 strncpy(dest, src, n); | 262 *os_error_message = strdup(strerror(errno)); |
| 263 dest[n - 1] = '\0'; | |
| 264 return dest; | |
| 265 } | 263 } |
| 266 | 264 |
| 267 | 265 |
| 268 static void SetChildOsErrorMessage(char* os_error_message, | |
| 269 int os_error_message_len) { | |
| 270 SafeStrNCpy(os_error_message, strerror(errno), os_error_message_len); | |
| 271 } | |
| 272 | |
| 273 | |
| 274 static void SigChldHandler(int process_signal, siginfo_t* siginfo, void* tmp) { | 266 static void SigChldHandler(int process_signal, siginfo_t* siginfo, void* tmp) { |
| 275 // Save errno so it can be restored at the end. | 267 // Save errno so it can be restored at the end. |
| 276 int entry_errno = errno; | 268 int entry_errno = errno; |
| 277 // Signal the exit code handler where the actual processing takes | 269 // Signal the exit code handler where the actual processing takes |
| 278 // place. | 270 // place. |
| 279 ssize_t result = | 271 ssize_t result = |
| 280 TEMP_FAILURE_RETRY(write(ExitCodeHandler::WakeUpFd(), "", 1)); | 272 TEMP_FAILURE_RETRY(write(ExitCodeHandler::WakeUpFd(), "", 1)); |
| 281 if (result < 1) { | 273 if (result < 1) { |
| 282 perror("Failed to write to wake-up fd in SIGCHLD handler"); | 274 perror("Failed to write to wake-up fd in SIGCHLD handler"); |
| 283 } | 275 } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 308 char* arguments[], | 300 char* arguments[], |
| 309 intptr_t arguments_length, | 301 intptr_t arguments_length, |
| 310 const char* working_directory, | 302 const char* working_directory, |
| 311 char* environment[], | 303 char* environment[], |
| 312 intptr_t environment_length, | 304 intptr_t environment_length, |
| 313 intptr_t* in, | 305 intptr_t* in, |
| 314 intptr_t* out, | 306 intptr_t* out, |
| 315 intptr_t* err, | 307 intptr_t* err, |
| 316 intptr_t* id, | 308 intptr_t* id, |
| 317 intptr_t* exit_event, | 309 intptr_t* exit_event, |
| 318 char* os_error_message, | 310 char** os_error_message) { |
| 319 int os_error_message_len) { | |
| 320 pid_t pid; | 311 pid_t pid; |
| 321 int read_in[2]; // Pipe for stdout to child process. | 312 int read_in[2]; // Pipe for stdout to child process. |
| 322 int read_err[2]; // Pipe for stderr to child process. | 313 int read_err[2]; // Pipe for stderr to child process. |
| 323 int write_out[2]; // Pipe for stdin to child process. | 314 int write_out[2]; // Pipe for stdin to child process. |
| 324 int exec_control[2]; // Pipe to get the result from exec. | 315 int exec_control[2]; // Pipe to get the result from exec. |
| 325 int result; | 316 int result; |
| 326 | 317 |
| 327 bool initialized = ExitCodeHandler::EnsureInitialized(); | 318 bool initialized = ExitCodeHandler::EnsureInitialized(); |
| 328 if (!initialized) { | 319 if (!initialized) { |
| 329 SetChildOsErrorMessage(os_error_message, os_error_message_len); | 320 SetChildOsErrorMessage(os_error_message); |
| 330 Log::PrintErr("Error initializing exit code handler: %s\n", | 321 Log::PrintErr("Error initializing exit code handler: %s\n", |
| 331 os_error_message); | 322 *os_error_message); |
| 332 return errno; | 323 return errno; |
| 333 } | 324 } |
| 334 | 325 |
| 335 result = TEMP_FAILURE_RETRY(pipe(read_in)); | 326 result = TEMP_FAILURE_RETRY(pipe(read_in)); |
| 336 if (result < 0) { | 327 if (result < 0) { |
| 337 SetChildOsErrorMessage(os_error_message, os_error_message_len); | 328 SetChildOsErrorMessage(os_error_message); |
| 338 Log::PrintErr("Error pipe creation failed: %s\n", os_error_message); | 329 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); |
| 339 return errno; | 330 return errno; |
| 340 } | 331 } |
| 341 | 332 |
| 342 result = TEMP_FAILURE_RETRY(pipe(read_err)); | 333 result = TEMP_FAILURE_RETRY(pipe(read_err)); |
| 343 if (result < 0) { | 334 if (result < 0) { |
| 344 SetChildOsErrorMessage(os_error_message, os_error_message_len); | 335 SetChildOsErrorMessage(os_error_message); |
| 345 TEMP_FAILURE_RETRY(close(read_in[0])); | 336 TEMP_FAILURE_RETRY(close(read_in[0])); |
| 346 TEMP_FAILURE_RETRY(close(read_in[1])); | 337 TEMP_FAILURE_RETRY(close(read_in[1])); |
| 347 Log::PrintErr("Error pipe creation failed: %s\n", os_error_message); | 338 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); |
| 348 return errno; | 339 return errno; |
| 349 } | 340 } |
| 350 | 341 |
| 351 result = TEMP_FAILURE_RETRY(pipe(write_out)); | 342 result = TEMP_FAILURE_RETRY(pipe(write_out)); |
| 352 if (result < 0) { | 343 if (result < 0) { |
| 353 SetChildOsErrorMessage(os_error_message, os_error_message_len); | 344 SetChildOsErrorMessage(os_error_message); |
| 354 TEMP_FAILURE_RETRY(close(read_in[0])); | 345 TEMP_FAILURE_RETRY(close(read_in[0])); |
| 355 TEMP_FAILURE_RETRY(close(read_in[1])); | 346 TEMP_FAILURE_RETRY(close(read_in[1])); |
| 356 TEMP_FAILURE_RETRY(close(read_err[0])); | 347 TEMP_FAILURE_RETRY(close(read_err[0])); |
| 357 TEMP_FAILURE_RETRY(close(read_err[1])); | 348 TEMP_FAILURE_RETRY(close(read_err[1])); |
| 358 Log::PrintErr("Error pipe creation failed: %s\n", os_error_message); | 349 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); |
| 359 return errno; | 350 return errno; |
| 360 } | 351 } |
| 361 | 352 |
| 362 result = TEMP_FAILURE_RETRY(pipe(exec_control)); | 353 result = TEMP_FAILURE_RETRY(pipe(exec_control)); |
| 363 if (result < 0) { | 354 if (result < 0) { |
| 364 SetChildOsErrorMessage(os_error_message, os_error_message_len); | 355 SetChildOsErrorMessage(os_error_message); |
| 365 TEMP_FAILURE_RETRY(close(read_in[0])); | 356 TEMP_FAILURE_RETRY(close(read_in[0])); |
| 366 TEMP_FAILURE_RETRY(close(read_in[1])); | 357 TEMP_FAILURE_RETRY(close(read_in[1])); |
| 367 TEMP_FAILURE_RETRY(close(read_err[0])); | 358 TEMP_FAILURE_RETRY(close(read_err[0])); |
| 368 TEMP_FAILURE_RETRY(close(read_err[1])); | 359 TEMP_FAILURE_RETRY(close(read_err[1])); |
| 369 TEMP_FAILURE_RETRY(close(write_out[0])); | 360 TEMP_FAILURE_RETRY(close(write_out[0])); |
| 370 TEMP_FAILURE_RETRY(close(write_out[1])); | 361 TEMP_FAILURE_RETRY(close(write_out[1])); |
| 371 Log::PrintErr("Error pipe creation failed: %s\n", os_error_message); | 362 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); |
| 372 return errno; | 363 return errno; |
| 373 } | 364 } |
| 374 | 365 |
| 375 // Set close on exec on the write file descriptor of the exec control pipe. | 366 // Set close on exec on the write file descriptor of the exec control pipe. |
| 376 result = TEMP_FAILURE_RETRY( | 367 result = TEMP_FAILURE_RETRY( |
| 377 fcntl(exec_control[1], | 368 fcntl(exec_control[1], |
| 378 F_SETFD, | 369 F_SETFD, |
| 379 TEMP_FAILURE_RETRY(fcntl(exec_control[1], F_GETFD)) | FD_CLOEXEC)); | 370 TEMP_FAILURE_RETRY(fcntl(exec_control[1], F_GETFD)) | FD_CLOEXEC)); |
| 380 if (result < 0) { | 371 if (result < 0) { |
| 381 SetChildOsErrorMessage(os_error_message, os_error_message_len); | 372 SetChildOsErrorMessage(os_error_message); |
| 382 TEMP_FAILURE_RETRY(close(read_in[0])); | 373 TEMP_FAILURE_RETRY(close(read_in[0])); |
| 383 TEMP_FAILURE_RETRY(close(read_in[1])); | 374 TEMP_FAILURE_RETRY(close(read_in[1])); |
| 384 TEMP_FAILURE_RETRY(close(read_err[0])); | 375 TEMP_FAILURE_RETRY(close(read_err[0])); |
| 385 TEMP_FAILURE_RETRY(close(read_err[1])); | 376 TEMP_FAILURE_RETRY(close(read_err[1])); |
| 386 TEMP_FAILURE_RETRY(close(write_out[0])); | 377 TEMP_FAILURE_RETRY(close(write_out[0])); |
| 387 TEMP_FAILURE_RETRY(close(write_out[1])); | 378 TEMP_FAILURE_RETRY(close(write_out[1])); |
| 388 TEMP_FAILURE_RETRY(close(exec_control[0])); | 379 TEMP_FAILURE_RETRY(close(exec_control[0])); |
| 389 TEMP_FAILURE_RETRY(close(exec_control[1])); | 380 TEMP_FAILURE_RETRY(close(exec_control[1])); |
| 390 Log::PrintErr("fcntl failed: %s\n", os_error_message); | 381 Log::PrintErr("fcntl failed: %s\n", *os_error_message); |
| 391 return errno; | 382 return errno; |
| 392 } | 383 } |
| 393 | 384 |
| 394 char** program_arguments = new char*[arguments_length + 2]; | 385 char** program_arguments = new char*[arguments_length + 2]; |
| 395 program_arguments[0] = const_cast<char*>(path); | 386 program_arguments[0] = const_cast<char*>(path); |
| 396 for (int i = 0; i < arguments_length; i++) { | 387 for (int i = 0; i < arguments_length; i++) { |
| 397 program_arguments[i + 1] = arguments[i]; | 388 program_arguments[i + 1] = arguments[i]; |
| 398 } | 389 } |
| 399 program_arguments[arguments_length + 1] = NULL; | 390 program_arguments[arguments_length + 1] = NULL; |
| 400 | 391 |
| 401 char** program_environment = NULL; | 392 char** program_environment = NULL; |
| 402 if (environment != NULL) { | 393 if (environment != NULL) { |
| 403 program_environment = new char*[environment_length + 1]; | 394 program_environment = new char*[environment_length + 1]; |
| 404 for (int i = 0; i < environment_length; i++) { | 395 for (int i = 0; i < environment_length; i++) { |
| 405 program_environment[i] = environment[i]; | 396 program_environment[i] = environment[i]; |
| 406 } | 397 } |
| 407 program_environment[environment_length] = NULL; | 398 program_environment[environment_length] = NULL; |
| 408 } | 399 } |
| 409 | 400 |
| 410 struct sigaction act; | 401 struct sigaction act; |
| 411 bzero(&act, sizeof(act)); | 402 bzero(&act, sizeof(act)); |
| 412 act.sa_sigaction = SigChldHandler; | 403 act.sa_sigaction = SigChldHandler; |
| 413 act.sa_flags = SA_NOCLDSTOP | SA_SIGINFO; | 404 act.sa_flags = SA_NOCLDSTOP | SA_SIGINFO; |
| 414 if (sigaction(SIGCHLD, &act, 0) != 0) { | 405 if (sigaction(SIGCHLD, &act, 0) != 0) { |
| 415 perror("Process start: setting signal handler failed"); | 406 perror("Process start: setting signal handler failed"); |
| 416 } | 407 } |
| 417 pid = TEMP_FAILURE_RETRY(fork()); | 408 pid = TEMP_FAILURE_RETRY(fork()); |
| 418 if (pid < 0) { | 409 if (pid < 0) { |
| 419 SetChildOsErrorMessage(os_error_message, os_error_message_len); | 410 SetChildOsErrorMessage(os_error_message); |
| 420 delete[] program_arguments; | 411 delete[] program_arguments; |
| 421 TEMP_FAILURE_RETRY(close(read_in[0])); | 412 TEMP_FAILURE_RETRY(close(read_in[0])); |
| 422 TEMP_FAILURE_RETRY(close(read_in[1])); | 413 TEMP_FAILURE_RETRY(close(read_in[1])); |
| 423 TEMP_FAILURE_RETRY(close(read_err[0])); | 414 TEMP_FAILURE_RETRY(close(read_err[0])); |
| 424 TEMP_FAILURE_RETRY(close(read_err[1])); | 415 TEMP_FAILURE_RETRY(close(read_err[1])); |
| 425 TEMP_FAILURE_RETRY(close(write_out[0])); | 416 TEMP_FAILURE_RETRY(close(write_out[0])); |
| 426 TEMP_FAILURE_RETRY(close(write_out[1])); | 417 TEMP_FAILURE_RETRY(close(write_out[1])); |
| 427 TEMP_FAILURE_RETRY(close(exec_control[0])); | 418 TEMP_FAILURE_RETRY(close(exec_control[0])); |
| 428 TEMP_FAILURE_RETRY(close(exec_control[1])); | 419 TEMP_FAILURE_RETRY(close(exec_control[1])); |
| 429 return errno; | 420 return errno; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 474 } | 465 } |
| 475 | 466 |
| 476 // The arguments and environment for the spawned process are not needed | 467 // The arguments and environment for the spawned process are not needed |
| 477 // any longer. | 468 // any longer. |
| 478 delete[] program_arguments; | 469 delete[] program_arguments; |
| 479 delete[] program_environment; | 470 delete[] program_environment; |
| 480 | 471 |
| 481 int event_fds[2]; | 472 int event_fds[2]; |
| 482 result = TEMP_FAILURE_RETRY(pipe(event_fds)); | 473 result = TEMP_FAILURE_RETRY(pipe(event_fds)); |
| 483 if (result < 0) { | 474 if (result < 0) { |
| 484 SetChildOsErrorMessage(os_error_message, os_error_message_len); | 475 SetChildOsErrorMessage(os_error_message); |
| 485 TEMP_FAILURE_RETRY(close(read_in[0])); | 476 TEMP_FAILURE_RETRY(close(read_in[0])); |
| 486 TEMP_FAILURE_RETRY(close(read_in[1])); | 477 TEMP_FAILURE_RETRY(close(read_in[1])); |
| 487 TEMP_FAILURE_RETRY(close(read_err[0])); | 478 TEMP_FAILURE_RETRY(close(read_err[0])); |
| 488 TEMP_FAILURE_RETRY(close(read_err[1])); | 479 TEMP_FAILURE_RETRY(close(read_err[1])); |
| 489 TEMP_FAILURE_RETRY(close(write_out[0])); | 480 TEMP_FAILURE_RETRY(close(write_out[0])); |
| 490 TEMP_FAILURE_RETRY(close(write_out[1])); | 481 TEMP_FAILURE_RETRY(close(write_out[1])); |
| 491 Log::PrintErr("Error pipe creation failed: %s\n", os_error_message); | 482 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); |
| 492 return errno; | 483 return errno; |
| 493 } | 484 } |
| 494 | 485 |
| 495 ProcessInfoList::AddProcess(pid, event_fds[1]); | 486 ProcessInfoList::AddProcess(pid, event_fds[1]); |
| 496 *exit_event = event_fds[0]; | 487 *exit_event = event_fds[0]; |
| 497 FDUtils::SetNonBlocking(event_fds[0]); | 488 FDUtils::SetNonBlocking(event_fds[0]); |
| 498 | 489 |
| 499 // Notify child process to start. | 490 // Notify child process to start. |
| 500 char msg = '1'; | 491 char msg = '1'; |
| 501 result = FDUtils::WriteToBlocking(read_in[1], &msg, sizeof(msg)); | 492 result = FDUtils::WriteToBlocking(read_in[1], &msg, sizeof(msg)); |
| 502 if (result != sizeof(msg)) { | 493 if (result != sizeof(msg)) { |
| 503 perror("Failed sending notification message"); | 494 perror("Failed sending notification message"); |
| 504 } | 495 } |
| 505 | 496 |
| 506 // Read exec result from child. If no data is returned the exec was | 497 // Read exec result from child. If no data is returned the exec was |
| 507 // successful and the exec call closed the pipe. Otherwise the errno | 498 // successful and the exec call closed the pipe. Otherwise the errno |
| 508 // is written to the pipe. | 499 // is written to the pipe. |
| 509 TEMP_FAILURE_RETRY(close(exec_control[1])); | 500 TEMP_FAILURE_RETRY(close(exec_control[1])); |
| 510 int child_errno; | 501 int child_errno; |
| 511 int bytes_read = -1; | 502 int bytes_read = -1; |
| 512 ASSERT(sizeof(child_errno) == sizeof(errno)); | 503 ASSERT(sizeof(child_errno) == sizeof(errno)); |
| 513 bytes_read = | 504 bytes_read = |
| 514 FDUtils::ReadFromBlocking( | 505 FDUtils::ReadFromBlocking( |
| 515 exec_control[0], &child_errno, sizeof(child_errno)); | 506 exec_control[0], &child_errno, sizeof(child_errno)); |
| 516 if (bytes_read == sizeof(child_errno)) { | 507 if (bytes_read == sizeof(child_errno)) { |
| 517 bytes_read = FDUtils::ReadFromBlocking(exec_control[0], | 508 static const int kMaxMessageSize = 256; |
| 518 os_error_message, | 509 char* message = static_cast<char*>(malloc(kMaxMessageSize)); |
| 519 os_error_message_len); | 510 bytes_read = FDUtils::ReadFromBlocking(exec_control[0], |
| 520 os_error_message[os_error_message_len - 1] = '\0'; | 511 message, |
| 512 kMaxMessageSize); |
| 513 message[kMaxMessageSize - 1] = '\0'; |
| 514 *os_error_message = message; |
| 521 } | 515 } |
| 522 TEMP_FAILURE_RETRY(close(exec_control[0])); | 516 TEMP_FAILURE_RETRY(close(exec_control[0])); |
| 523 | 517 |
| 524 // Return error code if any failures. | 518 // Return error code if any failures. |
| 525 if (bytes_read != 0) { | 519 if (bytes_read != 0) { |
| 526 TEMP_FAILURE_RETRY(close(read_in[0])); | 520 TEMP_FAILURE_RETRY(close(read_in[0])); |
| 527 TEMP_FAILURE_RETRY(close(read_in[1])); | 521 TEMP_FAILURE_RETRY(close(read_in[1])); |
| 528 TEMP_FAILURE_RETRY(close(read_err[0])); | 522 TEMP_FAILURE_RETRY(close(read_err[0])); |
| 529 TEMP_FAILURE_RETRY(close(read_err[1])); | 523 TEMP_FAILURE_RETRY(close(read_err[1])); |
| 530 TEMP_FAILURE_RETRY(close(write_out[0])); | 524 TEMP_FAILURE_RETRY(close(write_out[0])); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 561 | 555 |
| 562 | 556 |
| 563 void Process::TerminateExitCodeHandler() { | 557 void Process::TerminateExitCodeHandler() { |
| 564 ExitCodeHandler::TerminateExitCodeThread(); | 558 ExitCodeHandler::TerminateExitCodeThread(); |
| 565 } | 559 } |
| 566 | 560 |
| 567 | 561 |
| 568 intptr_t Process::CurrentProcessId() { | 562 intptr_t Process::CurrentProcessId() { |
| 569 return static_cast<intptr_t>(getpid()); | 563 return static_cast<intptr_t>(getpid()); |
| 570 } | 564 } |
| OLD | NEW |