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 |