Chromium Code Reviews| Index: runtime/bin/process_macos.cc |
| diff --git a/runtime/bin/process_macos.cc b/runtime/bin/process_macos.cc |
| index c87523c39194ab4e7b47d3dd611fc86934769d19..23de1fd525dfce66301f21d56869725aff2db445 100644 |
| --- a/runtime/bin/process_macos.cc |
| +++ b/runtime/bin/process_macos.cc |
| @@ -567,6 +567,130 @@ int Process::Start(const char* path, |
| } |
| +class BufferList: public BufferListBase { |
| + public: |
| + bool Read(int fd, intptr_t available) { |
| + // Read all available bytes. |
| + while (available > 0) { |
| + if (free_size_ == 0) Allocate(); |
| + ASSERT(free_size_ > 0); |
| + ASSERT(free_size_ <= kBufferSize); |
| + intptr_t block_size = dart::Utils::Minimum(free_size_, available); |
| + intptr_t bytes = TEMP_FAILURE_RETRY(read( |
| + fd, |
| + reinterpret_cast<void*>(tail_->data_ + (kBufferSize - free_size_)), |
|
Bill Hesse
2013/08/13 08:34:48
Maybe put the pointer to buffer free space in a me
Søren Gjesse
2013/08/13 13:00:43
Done.
|
| + block_size)); |
| + if (bytes < 0) return false; |
| + data_size_ += bytes; |
| + free_size_ -= bytes; |
| + available -= bytes; |
| + } |
| + return true; |
| + } |
| +}; |
| + |
| + |
| +static bool CloseProcessBuffers(struct pollfd fds[3]) { |
| + int e = errno; |
| + VOID_TEMP_FAILURE_RETRY(close(fds[0].fd)); |
| + VOID_TEMP_FAILURE_RETRY(close(fds[1].fd)); |
| + VOID_TEMP_FAILURE_RETRY(close(fds[2].fd)); |
| + errno = e; |
| + return false; |
| +} |
| + |
| + |
| +bool Process::Wait(intptr_t pid, |
| + intptr_t in, |
| + intptr_t out, |
| + intptr_t err, |
| + intptr_t exit_event, |
| + ProcessResult* result) { |
| + // Close input to the process right away. |
| + VOID_TEMP_FAILURE_RETRY(close(in)); |
| + |
| + // There is no return from this function using Dart_PropagateError |
| + // as memory used by the buffer lists is freed through their |
| + // destructors. |
| + BufferList out_data; |
| + BufferList err_data; |
| + union { |
| + uint8_t bytes[8]; |
| + int32_t ints[2]; |
| + } exit_code_data; |
| + |
| + struct pollfd fds[3]; |
| + fds[0].fd = out; |
| + fds[1].fd = err; |
| + fds[2].fd = exit_event; |
| + |
| + for (int i = 0; i < 3; i++) { |
| + fds[i].events = POLLIN; |
| + } |
| + |
| + int alive = 3; |
| + while (alive > 0) { |
| + // Blocking call waiting for events from the child process. |
| + if (TEMP_FAILURE_RETRY(poll(fds, alive, -1)) <= 0) { |
| + return CloseProcessBuffers(fds); |
| + } |
| + |
| + // Process incoming data. |
| + for (int i = 0; i < alive; i++) { |
| + if (fds[i].revents & POLLIN) { |
| + intptr_t avail = FDUtils::AvailableBytes(fds[i].fd); |
| + // On Mac OS POLLIN can be set with zero available |
| + // bytes. POLLHUP is most likely also set in this case. |
| + if (avail > 0) { |
| + if (fds[i].fd == out) { |
| + if (!out_data.Read(out, avail)) { |
| + return CloseProcessBuffers(fds); |
| + } |
| + } else if (fds[i].fd == err) { |
| + if (!err_data.Read(err, avail)) { |
| + return CloseProcessBuffers(fds); |
| + } |
| + } else if (fds[i].fd == exit_event) { |
| + if (avail == 8) { |
| + intptr_t b = TEMP_FAILURE_RETRY(read(fds[i].fd, |
| + exit_code_data.bytes, 8)); |
| + if (b != 8) { |
| + return CloseProcessBuffers(fds); |
| + } |
| + } |
| + } else { |
| + UNREACHABLE(); |
| + } |
| + } |
| + } |
| + } |
| + |
| + // Process closed. |
| + for (int i = 0; i < alive; i++) { |
| + if (fds[i].revents & POLLHUP) { |
| + VOID_TEMP_FAILURE_RETRY(close(fds[i].fd)); |
| + alive--; |
| + if (i < alive) { |
| + fds[i] = fds[alive]; |
| + } |
| + } |
| + } |
| + } |
| + |
| + // All handles closed and all data read. |
| + result->set_stdout_data(out_data.GetData()); |
| + result->set_stderr_data(err_data.GetData()); |
| + |
| + // Calculate the exit code. |
| + intptr_t exit_code = exit_code_data.ints[0]; |
| + intptr_t negative = exit_code_data.ints[1]; |
| + if (negative) exit_code = -exit_code; |
| + result->set_exit_code(exit_code); |
| + |
| + return true; |
| +} |
| + |
| + |
| bool Process::Kill(intptr_t id, int signal) { |
| return (TEMP_FAILURE_RETRY(kill(id, signal)) != -1); |
| } |