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