| 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 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 252 }; | 252 }; |
| 253 | 253 |
| 254 | 254 |
| 255 dart::Mutex ExitCodeHandler::mutex_; | 255 dart::Mutex ExitCodeHandler::mutex_; |
| 256 bool ExitCodeHandler::initialized_ = false; | 256 bool ExitCodeHandler::initialized_ = false; |
| 257 int ExitCodeHandler::sig_chld_fds_[2] = { 0, 0 }; | 257 int ExitCodeHandler::sig_chld_fds_[2] = { 0, 0 }; |
| 258 bool ExitCodeHandler::thread_terminated_ = false; | 258 bool ExitCodeHandler::thread_terminated_ = false; |
| 259 dart::Monitor ExitCodeHandler::thread_terminate_monitor_; | 259 dart::Monitor ExitCodeHandler::thread_terminate_monitor_; |
| 260 | 260 |
| 261 | 261 |
| 262 static char* SafeStrNCpy(char* dest, const char* src, size_t n) { | 262 static void SetChildOsErrorMessage(char** os_error_message) { |
| 263 strncpy(dest, src, n); | 263 *os_error_message = strdup(strerror(errno)); |
| 264 dest[n - 1] = '\0'; | |
| 265 return dest; | |
| 266 } | 264 } |
| 267 | 265 |
| 268 | 266 |
| 269 static void SetChildOsErrorMessage(char* os_error_message, | |
| 270 int os_error_message_len) { | |
| 271 SafeStrNCpy(os_error_message, strerror(errno), os_error_message_len); | |
| 272 } | |
| 273 | |
| 274 | |
| 275 static void SigChldHandler(int process_signal, siginfo_t* siginfo, void* tmp) { | 267 static void SigChldHandler(int process_signal, siginfo_t* siginfo, void* tmp) { |
| 276 // Save errno so it can be restored at the end. | 268 // Save errno so it can be restored at the end. |
| 277 int entry_errno = errno; | 269 int entry_errno = errno; |
| 278 // Signal the exit code handler where the actual processing takes | 270 // Signal the exit code handler where the actual processing takes |
| 279 // place. | 271 // place. |
| 280 ssize_t result = | 272 ssize_t result = |
| 281 TEMP_FAILURE_RETRY(write(ExitCodeHandler::WakeUpFd(), "", 1)); | 273 TEMP_FAILURE_RETRY(write(ExitCodeHandler::WakeUpFd(), "", 1)); |
| 282 if (result < 1) { | 274 if (result < 1) { |
| 283 perror("Failed to write to wake-up fd in SIGCHLD handler"); | 275 perror("Failed to write to wake-up fd in SIGCHLD handler"); |
| 284 } | 276 } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 309 char* arguments[], | 301 char* arguments[], |
| 310 intptr_t arguments_length, | 302 intptr_t arguments_length, |
| 311 const char* working_directory, | 303 const char* working_directory, |
| 312 char* environment[], | 304 char* environment[], |
| 313 intptr_t environment_length, | 305 intptr_t environment_length, |
| 314 intptr_t* in, | 306 intptr_t* in, |
| 315 intptr_t* out, | 307 intptr_t* out, |
| 316 intptr_t* err, | 308 intptr_t* err, |
| 317 intptr_t* id, | 309 intptr_t* id, |
| 318 intptr_t* exit_event, | 310 intptr_t* exit_event, |
| 319 char* os_error_message, | 311 char** os_error_message) { |
| 320 int os_error_message_len) { | |
| 321 pid_t pid; | 312 pid_t pid; |
| 322 int read_in[2]; // Pipe for stdout to child process. | 313 int read_in[2]; // Pipe for stdout to child process. |
| 323 int read_err[2]; // Pipe for stderr to child process. | 314 int read_err[2]; // Pipe for stderr to child process. |
| 324 int write_out[2]; // Pipe for stdin to child process. | 315 int write_out[2]; // Pipe for stdin to child process. |
| 325 int exec_control[2]; // Pipe to get the result from exec. | 316 int exec_control[2]; // Pipe to get the result from exec. |
| 326 int result; | 317 int result; |
| 327 | 318 |
| 328 bool initialized = ExitCodeHandler::EnsureInitialized(); | 319 bool initialized = ExitCodeHandler::EnsureInitialized(); |
| 329 if (!initialized) { | 320 if (!initialized) { |
| 330 SetChildOsErrorMessage(os_error_message, os_error_message_len); | 321 SetChildOsErrorMessage(os_error_message); |
| 331 Log::PrintErr( | 322 Log::PrintErr( |
| 332 "Error initializing exit code handler: %s\n", | 323 "Error initializing exit code handler: %s\n", |
| 333 os_error_message); | 324 *os_error_message); |
| 334 return errno; | 325 return errno; |
| 335 } | 326 } |
| 336 | 327 |
| 337 result = TEMP_FAILURE_RETRY(pipe(read_in)); | 328 result = TEMP_FAILURE_RETRY(pipe(read_in)); |
| 338 if (result < 0) { | 329 if (result < 0) { |
| 339 SetChildOsErrorMessage(os_error_message, os_error_message_len); | 330 SetChildOsErrorMessage(os_error_message); |
| 340 Log::PrintErr("Error pipe creation failed: %s\n", os_error_message); | 331 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); |
| 341 return errno; | 332 return errno; |
| 342 } | 333 } |
| 343 | 334 |
| 344 result = TEMP_FAILURE_RETRY(pipe(read_err)); | 335 result = TEMP_FAILURE_RETRY(pipe(read_err)); |
| 345 if (result < 0) { | 336 if (result < 0) { |
| 346 SetChildOsErrorMessage(os_error_message, os_error_message_len); | 337 SetChildOsErrorMessage(os_error_message); |
| 347 TEMP_FAILURE_RETRY(close(read_in[0])); | 338 TEMP_FAILURE_RETRY(close(read_in[0])); |
| 348 TEMP_FAILURE_RETRY(close(read_in[1])); | 339 TEMP_FAILURE_RETRY(close(read_in[1])); |
| 349 Log::PrintErr("Error pipe creation failed: %s\n", os_error_message); | 340 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); |
| 350 return errno; | 341 return errno; |
| 351 } | 342 } |
| 352 | 343 |
| 353 result = TEMP_FAILURE_RETRY(pipe(write_out)); | 344 result = TEMP_FAILURE_RETRY(pipe(write_out)); |
| 354 if (result < 0) { | 345 if (result < 0) { |
| 355 SetChildOsErrorMessage(os_error_message, os_error_message_len); | 346 SetChildOsErrorMessage(os_error_message); |
| 356 TEMP_FAILURE_RETRY(close(read_in[0])); | 347 TEMP_FAILURE_RETRY(close(read_in[0])); |
| 357 TEMP_FAILURE_RETRY(close(read_in[1])); | 348 TEMP_FAILURE_RETRY(close(read_in[1])); |
| 358 TEMP_FAILURE_RETRY(close(read_err[0])); | 349 TEMP_FAILURE_RETRY(close(read_err[0])); |
| 359 TEMP_FAILURE_RETRY(close(read_err[1])); | 350 TEMP_FAILURE_RETRY(close(read_err[1])); |
| 360 Log::PrintErr("Error pipe creation failed: %s\n", os_error_message); | 351 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); |
| 361 return errno; | 352 return errno; |
| 362 } | 353 } |
| 363 | 354 |
| 364 result = TEMP_FAILURE_RETRY(pipe(exec_control)); | 355 result = TEMP_FAILURE_RETRY(pipe(exec_control)); |
| 365 if (result < 0) { | 356 if (result < 0) { |
| 366 SetChildOsErrorMessage(os_error_message, os_error_message_len); | 357 SetChildOsErrorMessage(os_error_message); |
| 367 TEMP_FAILURE_RETRY(close(read_in[0])); | 358 TEMP_FAILURE_RETRY(close(read_in[0])); |
| 368 TEMP_FAILURE_RETRY(close(read_in[1])); | 359 TEMP_FAILURE_RETRY(close(read_in[1])); |
| 369 TEMP_FAILURE_RETRY(close(read_err[0])); | 360 TEMP_FAILURE_RETRY(close(read_err[0])); |
| 370 TEMP_FAILURE_RETRY(close(read_err[1])); | 361 TEMP_FAILURE_RETRY(close(read_err[1])); |
| 371 TEMP_FAILURE_RETRY(close(write_out[0])); | 362 TEMP_FAILURE_RETRY(close(write_out[0])); |
| 372 TEMP_FAILURE_RETRY(close(write_out[1])); | 363 TEMP_FAILURE_RETRY(close(write_out[1])); |
| 373 Log::PrintErr("Error pipe creation failed: %s\n", os_error_message); | 364 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); |
| 374 return errno; | 365 return errno; |
| 375 } | 366 } |
| 376 | 367 |
| 377 // Set close on exec on the write file descriptor of the exec control pipe. | 368 // Set close on exec on the write file descriptor of the exec control pipe. |
| 378 result = TEMP_FAILURE_RETRY( | 369 result = TEMP_FAILURE_RETRY( |
| 379 fcntl(exec_control[1], | 370 fcntl(exec_control[1], |
| 380 F_SETFD, | 371 F_SETFD, |
| 381 TEMP_FAILURE_RETRY(fcntl(exec_control[1], F_GETFD)) | FD_CLOEXEC)); | 372 TEMP_FAILURE_RETRY(fcntl(exec_control[1], F_GETFD)) | FD_CLOEXEC)); |
| 382 if (result < 0) { | 373 if (result < 0) { |
| 383 SetChildOsErrorMessage(os_error_message, os_error_message_len); | 374 SetChildOsErrorMessage(os_error_message); |
| 384 TEMP_FAILURE_RETRY(close(read_in[0])); | 375 TEMP_FAILURE_RETRY(close(read_in[0])); |
| 385 TEMP_FAILURE_RETRY(close(read_in[1])); | 376 TEMP_FAILURE_RETRY(close(read_in[1])); |
| 386 TEMP_FAILURE_RETRY(close(read_err[0])); | 377 TEMP_FAILURE_RETRY(close(read_err[0])); |
| 387 TEMP_FAILURE_RETRY(close(read_err[1])); | 378 TEMP_FAILURE_RETRY(close(read_err[1])); |
| 388 TEMP_FAILURE_RETRY(close(write_out[0])); | 379 TEMP_FAILURE_RETRY(close(write_out[0])); |
| 389 TEMP_FAILURE_RETRY(close(write_out[1])); | 380 TEMP_FAILURE_RETRY(close(write_out[1])); |
| 390 TEMP_FAILURE_RETRY(close(exec_control[0])); | 381 TEMP_FAILURE_RETRY(close(exec_control[0])); |
| 391 TEMP_FAILURE_RETRY(close(exec_control[1])); | 382 TEMP_FAILURE_RETRY(close(exec_control[1])); |
| 392 Log::PrintErr("fcntl failed: %s\n", os_error_message); | 383 Log::PrintErr("fcntl failed: %s\n", *os_error_message); |
| 393 return errno; | 384 return errno; |
| 394 } | 385 } |
| 395 | 386 |
| 396 char** program_arguments = new char*[arguments_length + 2]; | 387 char** program_arguments = new char*[arguments_length + 2]; |
| 397 program_arguments[0] = const_cast<char*>(path); | 388 program_arguments[0] = const_cast<char*>(path); |
| 398 for (int i = 0; i < arguments_length; i++) { | 389 for (int i = 0; i < arguments_length; i++) { |
| 399 program_arguments[i + 1] = arguments[i]; | 390 program_arguments[i + 1] = arguments[i]; |
| 400 } | 391 } |
| 401 program_arguments[arguments_length + 1] = NULL; | 392 program_arguments[arguments_length + 1] = NULL; |
| 402 | 393 |
| 403 char** program_environment = NULL; | 394 char** program_environment = NULL; |
| 404 if (environment != NULL) { | 395 if (environment != NULL) { |
| 405 program_environment = new char*[environment_length + 1]; | 396 program_environment = new char*[environment_length + 1]; |
| 406 for (int i = 0; i < environment_length; i++) { | 397 for (int i = 0; i < environment_length; i++) { |
| 407 program_environment[i] = environment[i]; | 398 program_environment[i] = environment[i]; |
| 408 } | 399 } |
| 409 program_environment[environment_length] = NULL; | 400 program_environment[environment_length] = NULL; |
| 410 } | 401 } |
| 411 | 402 |
| 412 struct sigaction act; | 403 struct sigaction act; |
| 413 bzero(&act, sizeof(act)); | 404 bzero(&act, sizeof(act)); |
| 414 act.sa_sigaction = SigChldHandler; | 405 act.sa_sigaction = SigChldHandler; |
| 415 act.sa_flags = SA_NOCLDSTOP | SA_SIGINFO; | 406 act.sa_flags = SA_NOCLDSTOP | SA_SIGINFO; |
| 416 if (sigaction(SIGCHLD, &act, 0) != 0) { | 407 if (sigaction(SIGCHLD, &act, 0) != 0) { |
| 417 perror("Process start: setting signal handler failed"); | 408 perror("Process start: setting signal handler failed"); |
| 418 } | 409 } |
| 419 pid = TEMP_FAILURE_RETRY(fork()); | 410 pid = TEMP_FAILURE_RETRY(fork()); |
| 420 if (pid < 0) { | 411 if (pid < 0) { |
| 421 SetChildOsErrorMessage(os_error_message, os_error_message_len); | 412 SetChildOsErrorMessage(os_error_message); |
| 422 delete[] program_arguments; | 413 delete[] program_arguments; |
| 423 TEMP_FAILURE_RETRY(close(read_in[0])); | 414 TEMP_FAILURE_RETRY(close(read_in[0])); |
| 424 TEMP_FAILURE_RETRY(close(read_in[1])); | 415 TEMP_FAILURE_RETRY(close(read_in[1])); |
| 425 TEMP_FAILURE_RETRY(close(read_err[0])); | 416 TEMP_FAILURE_RETRY(close(read_err[0])); |
| 426 TEMP_FAILURE_RETRY(close(read_err[1])); | 417 TEMP_FAILURE_RETRY(close(read_err[1])); |
| 427 TEMP_FAILURE_RETRY(close(write_out[0])); | 418 TEMP_FAILURE_RETRY(close(write_out[0])); |
| 428 TEMP_FAILURE_RETRY(close(write_out[1])); | 419 TEMP_FAILURE_RETRY(close(write_out[1])); |
| 429 TEMP_FAILURE_RETRY(close(exec_control[0])); | 420 TEMP_FAILURE_RETRY(close(exec_control[0])); |
| 430 TEMP_FAILURE_RETRY(close(exec_control[1])); | 421 TEMP_FAILURE_RETRY(close(exec_control[1])); |
| 431 return errno; | 422 return errno; |
| (...skipping 42 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 26 matching lines...) Expand all Loading... |
| 557 | 551 |
| 558 | 552 |
| 559 void Process::TerminateExitCodeHandler() { | 553 void Process::TerminateExitCodeHandler() { |
| 560 ExitCodeHandler::TerminateExitCodeThread(); | 554 ExitCodeHandler::TerminateExitCodeThread(); |
| 561 } | 555 } |
| 562 | 556 |
| 563 | 557 |
| 564 intptr_t Process::CurrentProcessId() { | 558 intptr_t Process::CurrentProcessId() { |
| 565 return static_cast<intptr_t>(getpid()); | 559 return static_cast<intptr_t>(getpid()); |
| 566 } | 560 } |
| OLD | NEW |