Chromium Code Reviews| 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 |