| Index: runtime/bin/process_win.cc
|
| diff --git a/runtime/bin/process_win.cc b/runtime/bin/process_win.cc
|
| index f6c809a75c550fd975b0afcc130016f2ff46d399..f8f09cc3b26eaabd6455da10d14db120840ffb4e 100644
|
| --- a/runtime/bin/process_win.cc
|
| +++ b/runtime/bin/process_win.cc
|
| @@ -642,6 +642,166 @@ int Process::Start(const char* path,
|
| }
|
|
|
|
|
| +class OverlappedHandle {
|
| + public:
|
| + static const int kBufferSize = 16 * 1024;
|
| +
|
| + void Init(HANDLE handle, HANDLE event) {
|
| + handle_ = handle;
|
| + event_ = event;
|
| + ClearOverlapped();
|
| + data_ = NULL;
|
| + data_length_ = 0;
|
| + }
|
| +
|
| + bool HasEvent(HANDLE event) {
|
| + return event_ == event;
|
| + }
|
| +
|
| + bool Read() {
|
| + // Get the data read as a rasult of a completed overlapped operation.
|
| + if (overlapped_.InternalHigh > 0) {
|
| + AddData(overlapped_.InternalHigh);
|
| + }
|
| +
|
| + // Keep reading until error or pending operation.
|
| + while (true) {
|
| + ClearOverlapped();
|
| + BOOL ok = ReadFile(handle_, buffer_, kBufferSize, NULL, &overlapped_);
|
| + if (!ok) return GetLastError() == ERROR_IO_PENDING;
|
| + AddData(overlapped_.InternalHigh);
|
| + }
|
| + }
|
| +
|
| + uint8_t* data() { return data_; }
|
| + intptr_t data_length() { return data_length_; }
|
| +
|
| + void Close() {
|
| + CloseHandle(handle_);
|
| + CloseHandle(event_);
|
| + handle_ = INVALID_HANDLE_VALUE;
|
| + overlapped_.hEvent = INVALID_HANDLE_VALUE;
|
| + }
|
| +
|
| + void FreeData() {
|
| + free(data_);
|
| + data_ = NULL;
|
| + data_length_ = 0;
|
| + }
|
| +
|
| + void Destroy() {
|
| + Close();
|
| + FreeData();
|
| + }
|
| +
|
| + private:
|
| + void ClearOverlapped() {
|
| + memset(&overlapped_, 0, sizeof(overlapped_));
|
| + overlapped_.hEvent = event_;
|
| + }
|
| +
|
| + void AddData(DWORD length) {
|
| + uint8_t* tmp = new uint8_t[data_length_ + length];
|
| + if (tmp == NULL) FATAL("Allocation failed");
|
| + memmove(tmp, data_, data_length_);
|
| + memmove(tmp + data_length_, buffer_, length);
|
| + delete[] data_;
|
| + data_ = tmp;
|
| + data_length_ += length;
|
| + }
|
| +
|
| + OVERLAPPED overlapped_;
|
| + HANDLE handle_;
|
| + HANDLE event_;
|
| + char buffer_[kBufferSize];
|
| + uint8_t* data_;
|
| + intptr_t data_length_;
|
| +
|
| + DISALLOW_ALLOCATION();
|
| +};
|
| +
|
| +
|
| +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.
|
| + reinterpret_cast<FileHandle*>(in)->Close();
|
| +
|
| + // All pipes created to the sub-process supports overlapped IO.
|
| + FileHandle* stdout_handle = reinterpret_cast<FileHandle*>(out);
|
| + ASSERT(stdout_handle->SupportsOverlappedIO());
|
| + FileHandle* stderr_handle = reinterpret_cast<FileHandle*>(err);
|
| + ASSERT(stderr_handle->SupportsOverlappedIO());
|
| + FileHandle* exit_handle = reinterpret_cast<FileHandle*>(exit_event);
|
| + ASSERT(exit_handle->SupportsOverlappedIO());
|
| +
|
| + // Create three events for overlapped IO. These are created as already
|
| + // signalled to ensure they have read called at least once.
|
| + static const int kHandles = 3;
|
| + HANDLE events[kHandles];
|
| + for (int i = 0; i < kHandles; i++) {
|
| + events[i] = CreateEvent(NULL, FALSE, TRUE, NULL);
|
| + }
|
| +
|
| + // Setup the structure for handling overlapped IO.
|
| + OverlappedHandle oh[kHandles];
|
| + memset(&oh, 0, sizeof(oh));
|
| + oh[0].Init(stdout_handle->handle(), events[0]);
|
| + oh[1].Init(stderr_handle->handle(), events[1]);
|
| + oh[2].Init(exit_handle->handle(), events[2]);
|
| +
|
| + // Continue until all handles are closed.
|
| + int alive = kHandles;
|
| + while (alive > 0) {
|
| + // Wait for event to become signalled.
|
| + DWORD wait_result = WaitForMultipleObjects(alive, events, FALSE, INFINITE);
|
| +
|
| + // Find the handle signalled.
|
| + int index = wait_result - WAIT_OBJECT_0;
|
| + for (int i = 0; i < kHandles; i++) {
|
| + if (oh[i].HasEvent(events[index])) {
|
| + bool ok = oh[i].Read();
|
| + if (!ok) {
|
| + if (GetLastError() == ERROR_BROKEN_PIPE) {
|
| + oh[i].Close();
|
| + alive--;
|
| + if (index < alive) {
|
| + events[index] = events[alive];
|
| + }
|
| + } else if (err != ERROR_IO_PENDING) {
|
| + DWORD e = GetLastError();
|
| + oh[0].Destroy();
|
| + oh[1].Destroy();
|
| + oh[2].Destroy();
|
| + SetLastError(e);
|
| + return false;
|
| + }
|
| + }
|
| + break;
|
| + }
|
| + }
|
| + }
|
| +
|
| + // All handles closed and all data read.
|
| + result->SetStdoutData(oh[0].data(), oh[0].data_length());
|
| + result->SetStderrData(oh[1].data(), oh[1].data_length());
|
| +
|
| + // Calculate the exit code.
|
| + ASSERT(oh[2].data_length() == 8);
|
| + uint32_t exit[2];
|
| + memcpy(&exit, oh[2].data(), sizeof(exit));
|
| + oh[2].FreeData();
|
| + intptr_t exit_code = exit[0];
|
| + intptr_t negative = exit[1];
|
| + if (negative) exit_code = -exit_code;
|
| + result->set_exit_code(exit_code);
|
| + return true;
|
| +}
|
| +
|
| +
|
| bool Process::Kill(intptr_t id, int signal) {
|
| USE(signal); // signal is not used on windows.
|
| HANDLE process_handle;
|
|
|