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_MACOS) | 6 #if defined(TARGET_OS_MACOS) |
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 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
251 exec_control_fd, &child_errno, sizeof(child_errno)); | 251 exec_control_fd, &child_errno, sizeof(child_errno)); |
252 if (bytes_written == sizeof(child_errno)) { | 252 if (bytes_written == sizeof(child_errno)) { |
253 FDUtils::WriteToBlocking( | 253 FDUtils::WriteToBlocking( |
254 exec_control_fd, os_error_message, strlen(os_error_message) + 1); | 254 exec_control_fd, os_error_message, strlen(os_error_message) + 1); |
255 } | 255 } |
256 VOID_TEMP_FAILURE_RETRY(close(exec_control_fd)); | 256 VOID_TEMP_FAILURE_RETRY(close(exec_control_fd)); |
257 exit(1); | 257 exit(1); |
258 } | 258 } |
259 | 259 |
260 | 260 |
| 261 static void ReportPid(int exec_control_fd, int pid) { |
| 262 // In the case of starting a detached process the actual pid of that process |
| 263 // is communicated using the exec control pipe. |
| 264 int bytes_written = |
| 265 FDUtils::WriteToBlocking(exec_control_fd, &pid, sizeof(pid)); |
| 266 ASSERT(bytes_written == sizeof(int)); |
| 267 USE(bytes_written); |
| 268 } |
| 269 |
| 270 |
| 271 static void ReadChildError(int exec_control_fd, char** error_message) { |
| 272 const int kMaxMessageSize = 256; |
| 273 char* message = static_cast<char*>(malloc(kMaxMessageSize)); |
| 274 if (message != NULL) { |
| 275 FDUtils::ReadFromBlocking(exec_control_fd, message, kMaxMessageSize); |
| 276 message[kMaxMessageSize - 1] = '\0'; |
| 277 *error_message = message; |
| 278 } else { |
| 279 static const char* no_message = "Cannot get error message, out of memory"; |
| 280 *error_message = const_cast<char*>(no_message); |
| 281 } |
| 282 } |
| 283 |
| 284 |
261 int Process::Start(const char* path, | 285 int Process::Start(const char* path, |
262 char* arguments[], | 286 char* arguments[], |
263 intptr_t arguments_length, | 287 intptr_t arguments_length, |
264 const char* working_directory, | 288 const char* working_directory, |
265 char* environment[], | 289 char* environment[], |
266 intptr_t environment_length, | 290 intptr_t environment_length, |
| 291 bool detach, |
267 intptr_t* in, | 292 intptr_t* in, |
268 intptr_t* out, | 293 intptr_t* out, |
269 intptr_t* err, | 294 intptr_t* err, |
270 intptr_t* id, | 295 intptr_t* id, |
271 intptr_t* exit_event, | 296 intptr_t* exit_event, |
272 char** os_error_message) { | 297 char** os_error_message) { |
273 pid_t pid; | 298 pid_t pid; |
274 int read_in[2]; // Pipe for stdout to child process. | 299 int read_in[2] = {-1, -1}; // Pipe for stdout to child process. |
275 int read_err[2]; // Pipe for stderr to child process. | 300 int read_err[2] = {-1, -1}; // Pipe for stderr to child process. |
276 int write_out[2]; // Pipe for stdin to child process. | 301 int write_out[2] = {-1, -1}; // Pipe for stdin to child process. |
277 int exec_control[2]; // Pipe to get the result from exec. | 302 int exec_control[2] = {-1, -1}; // Pipe to get the result from exec. |
278 int result; | 303 int result; |
279 | 304 |
280 result = TEMP_FAILURE_RETRY(pipe(read_in)); | |
281 if (result < 0) { | |
282 SetChildOsErrorMessage(os_error_message); | |
283 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); | |
284 return errno; | |
285 } | |
286 FDUtils::SetCloseOnExec(read_in[0]); | |
287 | |
288 result = TEMP_FAILURE_RETRY(pipe(read_err)); | |
289 if (result < 0) { | |
290 SetChildOsErrorMessage(os_error_message); | |
291 VOID_TEMP_FAILURE_RETRY(close(read_in[0])); | |
292 VOID_TEMP_FAILURE_RETRY(close(read_in[1])); | |
293 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); | |
294 return errno; | |
295 } | |
296 FDUtils::SetCloseOnExec(read_err[0]); | |
297 | |
298 result = TEMP_FAILURE_RETRY(pipe(write_out)); | |
299 if (result < 0) { | |
300 SetChildOsErrorMessage(os_error_message); | |
301 VOID_TEMP_FAILURE_RETRY(close(read_in[0])); | |
302 VOID_TEMP_FAILURE_RETRY(close(read_in[1])); | |
303 VOID_TEMP_FAILURE_RETRY(close(read_err[0])); | |
304 VOID_TEMP_FAILURE_RETRY(close(read_err[1])); | |
305 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); | |
306 return errno; | |
307 } | |
308 FDUtils::SetCloseOnExec(write_out[1]); | |
309 | |
310 result = TEMP_FAILURE_RETRY(pipe(exec_control)); | 305 result = TEMP_FAILURE_RETRY(pipe(exec_control)); |
311 if (result < 0) { | 306 if (result < 0) { |
312 SetChildOsErrorMessage(os_error_message); | 307 SetChildOsErrorMessage(os_error_message); |
313 VOID_TEMP_FAILURE_RETRY(close(read_in[0])); | |
314 VOID_TEMP_FAILURE_RETRY(close(read_in[1])); | |
315 VOID_TEMP_FAILURE_RETRY(close(read_err[0])); | |
316 VOID_TEMP_FAILURE_RETRY(close(read_err[1])); | |
317 VOID_TEMP_FAILURE_RETRY(close(write_out[0])); | |
318 VOID_TEMP_FAILURE_RETRY(close(write_out[1])); | |
319 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); | 308 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); |
320 return errno; | 309 return errno; |
321 } | 310 } |
322 FDUtils::SetCloseOnExec(exec_control[0]); | 311 FDUtils::SetCloseOnExec(exec_control[0]); |
323 FDUtils::SetCloseOnExec(exec_control[1]); | 312 FDUtils::SetCloseOnExec(exec_control[1]); |
324 | 313 |
| 314 // For a detached process the pipe to connect stdout is still used for |
| 315 // signaling when to do the first fork. |
| 316 result = TEMP_FAILURE_RETRY(pipe(read_in)); |
325 if (result < 0) { | 317 if (result < 0) { |
326 SetChildOsErrorMessage(os_error_message); | 318 SetChildOsErrorMessage(os_error_message); |
327 VOID_TEMP_FAILURE_RETRY(close(read_in[0])); | |
328 VOID_TEMP_FAILURE_RETRY(close(read_in[1])); | |
329 VOID_TEMP_FAILURE_RETRY(close(read_err[0])); | |
330 VOID_TEMP_FAILURE_RETRY(close(read_err[1])); | |
331 VOID_TEMP_FAILURE_RETRY(close(write_out[0])); | |
332 VOID_TEMP_FAILURE_RETRY(close(write_out[1])); | |
333 VOID_TEMP_FAILURE_RETRY(close(exec_control[0])); | 319 VOID_TEMP_FAILURE_RETRY(close(exec_control[0])); |
334 VOID_TEMP_FAILURE_RETRY(close(exec_control[1])); | 320 VOID_TEMP_FAILURE_RETRY(close(exec_control[1])); |
335 Log::PrintErr("fcntl failed: %s\n", *os_error_message); | 321 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); |
336 return errno; | 322 return errno; |
337 } | 323 } |
| 324 FDUtils::SetCloseOnExec(read_in[0]); |
| 325 |
| 326 // For detached processes the pipe to connect stderr and stdin are not used. |
| 327 if (!detach) { |
| 328 result = TEMP_FAILURE_RETRY(pipe(read_err)); |
| 329 if (result < 0) { |
| 330 SetChildOsErrorMessage(os_error_message); |
| 331 VOID_TEMP_FAILURE_RETRY(close(exec_control[0])); |
| 332 VOID_TEMP_FAILURE_RETRY(close(exec_control[1])); |
| 333 VOID_TEMP_FAILURE_RETRY(close(read_in[0])); |
| 334 VOID_TEMP_FAILURE_RETRY(close(read_in[1])); |
| 335 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); |
| 336 return errno; |
| 337 } |
| 338 FDUtils::SetCloseOnExec(read_err[0]); |
| 339 |
| 340 result = TEMP_FAILURE_RETRY(pipe(write_out)); |
| 341 if (result < 0) { |
| 342 SetChildOsErrorMessage(os_error_message); |
| 343 VOID_TEMP_FAILURE_RETRY(close(exec_control[0])); |
| 344 VOID_TEMP_FAILURE_RETRY(close(exec_control[1])); |
| 345 VOID_TEMP_FAILURE_RETRY(close(read_in[0])); |
| 346 VOID_TEMP_FAILURE_RETRY(close(read_in[1])); |
| 347 VOID_TEMP_FAILURE_RETRY(close(read_err[0])); |
| 348 VOID_TEMP_FAILURE_RETRY(close(read_err[1])); |
| 349 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); |
| 350 return errno; |
| 351 } |
| 352 FDUtils::SetCloseOnExec(write_out[1]); |
| 353 } |
338 | 354 |
339 char** program_arguments = new char*[arguments_length + 2]; | 355 char** program_arguments = new char*[arguments_length + 2]; |
340 program_arguments[0] = const_cast<char*>(path); | 356 program_arguments[0] = const_cast<char*>(path); |
341 for (int i = 0; i < arguments_length; i++) { | 357 for (int i = 0; i < arguments_length; i++) { |
342 program_arguments[i + 1] = arguments[i]; | 358 program_arguments[i + 1] = arguments[i]; |
343 } | 359 } |
344 program_arguments[arguments_length + 1] = NULL; | 360 program_arguments[arguments_length + 1] = NULL; |
345 | 361 |
346 char** program_environment = NULL; | 362 char** program_environment = NULL; |
347 if (environment != NULL) { | 363 if (environment != NULL) { |
348 program_environment = new char*[environment_length + 1]; | 364 program_environment = new char*[environment_length + 1]; |
349 for (int i = 0; i < environment_length; i++) { | 365 for (int i = 0; i < environment_length; i++) { |
350 program_environment[i] = environment[i]; | 366 program_environment[i] = environment[i]; |
351 } | 367 } |
352 program_environment[environment_length] = NULL; | 368 program_environment[environment_length] = NULL; |
353 } | 369 } |
354 | 370 |
355 pid = TEMP_FAILURE_RETRY(fork()); | 371 pid = TEMP_FAILURE_RETRY(fork()); |
356 if (pid < 0) { | 372 if (pid < 0) { |
357 SetChildOsErrorMessage(os_error_message); | 373 SetChildOsErrorMessage(os_error_message); |
358 delete[] program_arguments; | 374 delete[] program_arguments; |
| 375 VOID_TEMP_FAILURE_RETRY(close(exec_control[0])); |
| 376 VOID_TEMP_FAILURE_RETRY(close(exec_control[1])); |
359 VOID_TEMP_FAILURE_RETRY(close(read_in[0])); | 377 VOID_TEMP_FAILURE_RETRY(close(read_in[0])); |
360 VOID_TEMP_FAILURE_RETRY(close(read_in[1])); | 378 VOID_TEMP_FAILURE_RETRY(close(read_in[1])); |
361 VOID_TEMP_FAILURE_RETRY(close(read_err[0])); | 379 if (detach) { |
362 VOID_TEMP_FAILURE_RETRY(close(read_err[1])); | 380 VOID_TEMP_FAILURE_RETRY(close(read_err[0])); |
363 VOID_TEMP_FAILURE_RETRY(close(write_out[0])); | 381 VOID_TEMP_FAILURE_RETRY(close(read_err[1])); |
364 VOID_TEMP_FAILURE_RETRY(close(write_out[1])); | 382 VOID_TEMP_FAILURE_RETRY(close(write_out[0])); |
365 VOID_TEMP_FAILURE_RETRY(close(exec_control[0])); | 383 VOID_TEMP_FAILURE_RETRY(close(write_out[1])); |
366 VOID_TEMP_FAILURE_RETRY(close(exec_control[1])); | 384 } |
367 return errno; | 385 return errno; |
368 } else if (pid == 0) { | 386 } else if (pid == 0) { |
369 // Wait for parent process before setting up the child process. | 387 // Wait for parent process before setting up the child process. |
370 char msg; | 388 char msg; |
371 int bytes_read = FDUtils::ReadFromBlocking(read_in[0], &msg, sizeof(msg)); | 389 int bytes_read = FDUtils::ReadFromBlocking(read_in[0], &msg, sizeof(msg)); |
372 if (bytes_read != sizeof(msg)) { | 390 if (bytes_read != sizeof(msg)) { |
373 perror("Failed receiving notification message"); | 391 perror("Failed receiving notification message"); |
374 exit(1); | 392 exit(1); |
375 } | 393 } |
| 394 if (detach) { |
| 395 // For a detached process the pipe to connect stdout is only used for |
| 396 // signaling when to do the first fork. |
| 397 VOID_TEMP_FAILURE_RETRY(close(read_in[0])); |
| 398 VOID_TEMP_FAILURE_RETRY(close(read_in[1])); |
| 399 // Fork once more to start a new session. |
| 400 pid = TEMP_FAILURE_RETRY(fork()); |
| 401 if (pid < 0) { |
| 402 ReportChildError(exec_control[1]); |
| 403 } else if (pid == 0) { |
| 404 // Start a new session. |
| 405 if (TEMP_FAILURE_RETRY(setsid()) == -1) { |
| 406 ReportChildError(exec_control[1]); |
| 407 } else { |
| 408 // Do a final fork to not be the session leader. |
| 409 pid = TEMP_FAILURE_RETRY(fork()); |
| 410 if (pid < 0) { |
| 411 ReportChildError(exec_control[1]); |
| 412 } else if (pid == 0) { |
| 413 // Close all open file descriptors except for exec_control[1]. |
| 414 int max_fds = sysconf(_SC_OPEN_MAX); |
| 415 if (max_fds == -1) max_fds = _POSIX_OPEN_MAX; |
| 416 for (int fd = 0; fd < max_fds; fd++) { |
| 417 if (fd != exec_control[1]) { |
| 418 VOID_TEMP_FAILURE_RETRY(close(fd)); |
| 419 } |
| 420 } |
376 | 421 |
377 VOID_TEMP_FAILURE_RETRY(close(write_out[1])); | 422 // Re-open stdin, stdout and stderr and connect them to /dev/null. |
378 VOID_TEMP_FAILURE_RETRY(close(read_in[0])); | 423 // The loop above should already have closed all of them, so |
379 VOID_TEMP_FAILURE_RETRY(close(read_err[0])); | 424 // creating new file descriptors should start at STDIN_FILENO. |
380 VOID_TEMP_FAILURE_RETRY(close(exec_control[0])); | 425 int fd = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)); |
| 426 if (fd != STDIN_FILENO) { |
| 427 ReportChildError(exec_control[1]); |
| 428 } |
| 429 if (TEMP_FAILURE_RETRY(dup2(STDIN_FILENO, STDOUT_FILENO)) != |
| 430 STDOUT_FILENO) { |
| 431 ReportChildError(exec_control[1]); |
| 432 } |
| 433 if (TEMP_FAILURE_RETRY(dup2(STDIN_FILENO, STDERR_FILENO)) != |
| 434 STDERR_FILENO) { |
| 435 ReportChildError(exec_control[1]); |
| 436 } |
381 | 437 |
382 if (TEMP_FAILURE_RETRY(dup2(write_out[0], STDIN_FILENO)) == -1) { | 438 // Report the final PID and do the exec. |
| 439 ReportPid(exec_control[1], getpid()); // getpid cannot fail. |
| 440 VOID_TEMP_FAILURE_RETRY( |
| 441 execvp(path, const_cast<char* const*>(program_arguments))); |
| 442 ReportChildError(exec_control[1]); |
| 443 } else { |
| 444 exit(0); |
| 445 } |
| 446 } |
| 447 } else { |
| 448 exit(0); |
| 449 } |
| 450 } else { |
| 451 VOID_TEMP_FAILURE_RETRY(close(write_out[1])); |
| 452 VOID_TEMP_FAILURE_RETRY(close(read_in[0])); |
| 453 VOID_TEMP_FAILURE_RETRY(close(read_err[0])); |
| 454 VOID_TEMP_FAILURE_RETRY(close(exec_control[0])); |
| 455 |
| 456 if (TEMP_FAILURE_RETRY(dup2(write_out[0], STDIN_FILENO)) == -1) { |
| 457 ReportChildError(exec_control[1]); |
| 458 } |
| 459 VOID_TEMP_FAILURE_RETRY(close(write_out[0])); |
| 460 |
| 461 if (TEMP_FAILURE_RETRY(dup2(read_in[1], STDOUT_FILENO)) == -1) { |
| 462 ReportChildError(exec_control[1]); |
| 463 } |
| 464 VOID_TEMP_FAILURE_RETRY(close(read_in[1])); |
| 465 |
| 466 if (TEMP_FAILURE_RETRY(dup2(read_err[1], STDERR_FILENO)) == -1) { |
| 467 ReportChildError(exec_control[1]); |
| 468 } |
| 469 VOID_TEMP_FAILURE_RETRY(close(read_err[1])); |
| 470 |
| 471 if (working_directory != NULL && |
| 472 TEMP_FAILURE_RETRY(chdir(working_directory)) == -1) { |
| 473 ReportChildError(exec_control[1]); |
| 474 } |
| 475 |
| 476 if (program_environment != NULL) { |
| 477 environ = program_environment; |
| 478 } |
| 479 |
| 480 VOID_TEMP_FAILURE_RETRY( |
| 481 execvp(path, const_cast<char* const*>(program_arguments))); |
| 482 |
383 ReportChildError(exec_control[1]); | 483 ReportChildError(exec_control[1]); |
384 } | 484 } |
385 VOID_TEMP_FAILURE_RETRY(close(write_out[0])); | |
386 | |
387 if (TEMP_FAILURE_RETRY(dup2(read_in[1], STDOUT_FILENO)) == -1) { | |
388 ReportChildError(exec_control[1]); | |
389 } | |
390 VOID_TEMP_FAILURE_RETRY(close(read_in[1])); | |
391 | |
392 if (TEMP_FAILURE_RETRY(dup2(read_err[1], STDERR_FILENO)) == -1) { | |
393 ReportChildError(exec_control[1]); | |
394 } | |
395 VOID_TEMP_FAILURE_RETRY(close(read_err[1])); | |
396 | |
397 if (working_directory != NULL && | |
398 TEMP_FAILURE_RETRY(chdir(working_directory)) == -1) { | |
399 ReportChildError(exec_control[1]); | |
400 } | |
401 | |
402 if (program_environment != NULL) { | |
403 environ = program_environment; | |
404 } | |
405 | |
406 VOID_TEMP_FAILURE_RETRY( | |
407 execvp(path, const_cast<char* const*>(program_arguments))); | |
408 | |
409 ReportChildError(exec_control[1]); | |
410 } | 485 } |
411 | 486 |
412 // Be sure to listen for exit-codes, now we have a child-process. | 487 // Be sure to listen for exit-codes, now we have a child-process. |
413 ExitCodeHandler::ProcessStarted(); | 488 ExitCodeHandler::ProcessStarted(); |
414 | 489 |
415 // The arguments and environment for the spawned process are not needed | 490 // The arguments and environment for the spawned process are not needed |
416 // any longer. | 491 // any longer. |
417 delete[] program_arguments; | 492 delete[] program_arguments; |
418 delete[] program_environment; | 493 delete[] program_environment; |
419 | 494 |
420 int event_fds[2]; | 495 if (!detach) { |
421 result = TEMP_FAILURE_RETRY(pipe(event_fds)); | 496 int event_fds[2]; |
422 if (result < 0) { | 497 result = TEMP_FAILURE_RETRY(pipe(event_fds)); |
423 SetChildOsErrorMessage(os_error_message); | 498 if (result < 0) { |
424 VOID_TEMP_FAILURE_RETRY(close(read_in[0])); | 499 SetChildOsErrorMessage(os_error_message); |
425 VOID_TEMP_FAILURE_RETRY(close(read_in[1])); | 500 VOID_TEMP_FAILURE_RETRY(close(read_in[0])); |
426 VOID_TEMP_FAILURE_RETRY(close(read_err[0])); | 501 VOID_TEMP_FAILURE_RETRY(close(read_in[1])); |
427 VOID_TEMP_FAILURE_RETRY(close(read_err[1])); | 502 VOID_TEMP_FAILURE_RETRY(close(read_err[0])); |
428 VOID_TEMP_FAILURE_RETRY(close(write_out[0])); | 503 VOID_TEMP_FAILURE_RETRY(close(read_err[1])); |
429 VOID_TEMP_FAILURE_RETRY(close(write_out[1])); | 504 VOID_TEMP_FAILURE_RETRY(close(write_out[0])); |
430 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); | 505 VOID_TEMP_FAILURE_RETRY(close(write_out[1])); |
431 return errno; | 506 Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message); |
| 507 return errno; |
| 508 } |
| 509 FDUtils::SetCloseOnExec(event_fds[0]); |
| 510 FDUtils::SetCloseOnExec(event_fds[1]); |
| 511 |
| 512 ProcessInfoList::AddProcess(pid, event_fds[1]); |
| 513 *exit_event = event_fds[0]; |
| 514 FDUtils::SetNonBlocking(event_fds[0]); |
432 } | 515 } |
433 FDUtils::SetCloseOnExec(event_fds[0]); | |
434 FDUtils::SetCloseOnExec(event_fds[1]); | |
435 | |
436 ProcessInfoList::AddProcess(pid, event_fds[1]); | |
437 *exit_event = event_fds[0]; | |
438 FDUtils::SetNonBlocking(event_fds[0]); | |
439 | 516 |
440 // Notify child process to start. | 517 // Notify child process to start. |
441 char msg = '1'; | 518 char msg = '1'; |
442 result = FDUtils::WriteToBlocking(read_in[1], &msg, sizeof(msg)); | 519 result = FDUtils::WriteToBlocking(read_in[1], &msg, sizeof(msg)); |
443 if (result != sizeof(msg)) { | 520 if (result != sizeof(msg)) { |
444 perror("Failed sending notification message"); | 521 perror("Failed sending notification message"); |
445 } | 522 } |
446 | 523 |
447 // Read exec result from child. If no data is returned the exec was | 524 // Read exec result from child. If no data is returned the exec was |
448 // successful and the exec call closed the pipe. Otherwise the errno | 525 // successful and the exec call closed the pipe. Otherwise the errno |
449 // is written to the pipe. | 526 // is written to the pipe. |
450 VOID_TEMP_FAILURE_RETRY(close(exec_control[1])); | 527 VOID_TEMP_FAILURE_RETRY(close(exec_control[1])); |
| 528 bool failed = false; |
451 int child_errno; | 529 int child_errno; |
452 int bytes_read = -1; | 530 int bytes_read = -1; |
453 ASSERT(sizeof(child_errno) == sizeof(errno)); | 531 ASSERT(sizeof(child_errno) == sizeof(errno)); |
454 bytes_read = | 532 if (!detach) { |
455 FDUtils::ReadFromBlocking( | 533 // Read exec result from child. If no data is returned the exec was |
456 exec_control[0], &child_errno, sizeof(child_errno)); | 534 // successful and the exec call closed the pipe. Otherwise the errno |
457 if (bytes_read == sizeof(child_errno)) { | 535 // is written to the pipe. |
458 static const int kMaxMessageSize = 256; | 536 bytes_read = |
459 char* message = static_cast<char*>(malloc(kMaxMessageSize)); | 537 FDUtils::ReadFromBlocking( |
460 bytes_read = FDUtils::ReadFromBlocking(exec_control[0], | 538 exec_control[0], &child_errno, sizeof(child_errno)); |
461 message, | 539 if (bytes_read == sizeof(child_errno)) { |
462 kMaxMessageSize); | 540 ReadChildError(exec_control[0], os_error_message); |
463 message[kMaxMessageSize - 1] = '\0'; | 541 failed = true; |
464 *os_error_message = message; | 542 } |
| 543 } else { |
| 544 // Read exec result from child. If only pid data is returned the exec was |
| 545 // successful and the exec call closed the pipe. Otherwise the errno |
| 546 // is written to the pipe as well. |
| 547 int result[2]; |
| 548 ASSERT(sizeof(int) == sizeof(child_errno)); |
| 549 bytes_read = |
| 550 FDUtils::ReadFromBlocking( |
| 551 exec_control[0], result, sizeof(result)); |
| 552 if (bytes_read == sizeof(int)) { |
| 553 pid = result[0]; |
| 554 } else if (bytes_read == 2 * sizeof(int)) { |
| 555 pid = result[0]; |
| 556 child_errno = result[1]; |
| 557 ReadChildError(exec_control[0], os_error_message); |
| 558 failed = true; |
| 559 } |
465 } | 560 } |
466 VOID_TEMP_FAILURE_RETRY(close(exec_control[0])); | 561 VOID_TEMP_FAILURE_RETRY(close(exec_control[0])); |
467 | 562 |
468 // Return error code if any failures. | 563 // Return error code if any failures. |
469 if (bytes_read != 0) { | 564 if (failed) { |
470 VOID_TEMP_FAILURE_RETRY(close(read_in[0])); | 565 if (!detach) { |
471 VOID_TEMP_FAILURE_RETRY(close(read_in[1])); | 566 VOID_TEMP_FAILURE_RETRY(close(read_in[0])); |
472 VOID_TEMP_FAILURE_RETRY(close(read_err[0])); | 567 VOID_TEMP_FAILURE_RETRY(close(read_in[1])); |
473 VOID_TEMP_FAILURE_RETRY(close(read_err[1])); | 568 VOID_TEMP_FAILURE_RETRY(close(read_err[0])); |
474 VOID_TEMP_FAILURE_RETRY(close(write_out[0])); | 569 VOID_TEMP_FAILURE_RETRY(close(read_err[1])); |
475 VOID_TEMP_FAILURE_RETRY(close(write_out[1])); | 570 VOID_TEMP_FAILURE_RETRY(close(write_out[0])); |
| 571 VOID_TEMP_FAILURE_RETRY(close(write_out[1])); |
476 | 572 |
477 // Since exec() failed, we're not interested in the exit code. | 573 // Since exec() failed, we're not interested in the exit code. |
478 // We close the reading side of the exit code pipe here. | 574 // We close the reading side of the exit code pipe here. |
479 // GetProcessExitCodes will get a broken pipe error when it tries to write | 575 // GetProcessExitCodes will get a broken pipe error when it tries to write |
480 // to the writing side of the pipe and it will ignore the error. | 576 // to the writing side of the pipe and it will ignore the error. |
481 VOID_TEMP_FAILURE_RETRY(close(*exit_event)); | 577 VOID_TEMP_FAILURE_RETRY(close(*exit_event)); |
482 *exit_event = -1; | 578 *exit_event = -1; |
483 | 579 } |
484 if (bytes_read == -1) { | 580 if (bytes_read == -1) { |
485 return errno; // Read failed. | 581 return errno; // Read failed. |
486 } else { | 582 } else { |
487 return child_errno; // Exec failed. | 583 return child_errno; // Exec failed. |
488 } | 584 } |
489 } | 585 } |
490 | 586 |
491 FDUtils::SetNonBlocking(read_in[0]); | 587 FDUtils::SetNonBlocking(read_in[0]); |
492 *in = read_in[0]; | 588 *in = read_in[0]; |
493 VOID_TEMP_FAILURE_RETRY(close(read_in[1])); | 589 VOID_TEMP_FAILURE_RETRY(close(read_in[1])); |
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
789 bzero(&act, sizeof(act)); | 885 bzero(&act, sizeof(act)); |
790 act.sa_handler = SIG_DFL; | 886 act.sa_handler = SIG_DFL; |
791 VOID_NO_RETRY_EXPECTED(sigaction(signal, &act, NULL)); | 887 VOID_NO_RETRY_EXPECTED(sigaction(signal, &act, NULL)); |
792 } | 888 } |
793 } | 889 } |
794 | 890 |
795 } // namespace bin | 891 } // namespace bin |
796 } // namespace dart | 892 } // namespace dart |
797 | 893 |
798 #endif // defined(TARGET_OS_MACOS) | 894 #endif // defined(TARGET_OS_MACOS) |
OLD | NEW |