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