| 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_WINDOWS) | 6 #if defined(TARGET_OS_WINDOWS) |
| 7 | 7 |
| 8 #include <process.h> // NOLINT | 8 #include <process.h> // NOLINT |
| 9 | 9 |
| 10 #include "bin/builtin.h" | 10 #include "bin/builtin.h" |
| (...skipping 624 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 635 *exit_handler = reinterpret_cast<intptr_t>(exit_handle); | 635 *exit_handler = reinterpret_cast<intptr_t>(exit_handle); |
| 636 | 636 |
| 637 CloseHandle(process_info.hThread); | 637 CloseHandle(process_info.hThread); |
| 638 | 638 |
| 639 // Return process id. | 639 // Return process id. |
| 640 *id = process_info.dwProcessId; | 640 *id = process_info.dwProcessId; |
| 641 return 0; | 641 return 0; |
| 642 } | 642 } |
| 643 | 643 |
| 644 | 644 |
| 645 class OverlappedHandle { |
| 646 public: |
| 647 static const int kBufferSize = 16 * 1024; |
| 648 |
| 649 void Init(HANDLE handle, HANDLE event) { |
| 650 handle_ = handle; |
| 651 event_ = event; |
| 652 ClearOverlapped(); |
| 653 data_ = NULL; |
| 654 data_length_ = 0; |
| 655 } |
| 656 |
| 657 bool HasEvent(HANDLE event) { |
| 658 return event_ == event; |
| 659 } |
| 660 |
| 661 bool Read() { |
| 662 // Get the data read as a rasult of a completed overlapped operation. |
| 663 if (overlapped_.InternalHigh > 0) { |
| 664 AddData(overlapped_.InternalHigh); |
| 665 } |
| 666 |
| 667 // Keep reading until error or pending operation. |
| 668 while (true) { |
| 669 ClearOverlapped(); |
| 670 BOOL ok = ReadFile(handle_, buffer_, kBufferSize, NULL, &overlapped_); |
| 671 if (!ok) return GetLastError() == ERROR_IO_PENDING; |
| 672 AddData(overlapped_.InternalHigh); |
| 673 } |
| 674 } |
| 675 |
| 676 uint8_t* data() { return data_; } |
| 677 intptr_t data_length() { return data_length_; } |
| 678 |
| 679 void Close() { |
| 680 CloseHandle(handle_); |
| 681 CloseHandle(event_); |
| 682 handle_ = INVALID_HANDLE_VALUE; |
| 683 overlapped_.hEvent = INVALID_HANDLE_VALUE; |
| 684 } |
| 685 |
| 686 void FreeData() { |
| 687 free(data_); |
| 688 data_ = NULL; |
| 689 data_length_ = 0; |
| 690 } |
| 691 |
| 692 void Destroy() { |
| 693 Close(); |
| 694 FreeData(); |
| 695 } |
| 696 |
| 697 private: |
| 698 void ClearOverlapped() { |
| 699 memset(&overlapped_, 0, sizeof(overlapped_)); |
| 700 overlapped_.hEvent = event_; |
| 701 } |
| 702 |
| 703 void AddData(DWORD length) { |
| 704 uint8_t* tmp = new uint8_t[data_length_ + length]; |
| 705 if (tmp == NULL) FATAL("Allocation failed"); |
| 706 memmove(tmp, data_, data_length_); |
| 707 memmove(tmp + data_length_, buffer_, length); |
| 708 delete[] data_; |
| 709 data_ = tmp; |
| 710 data_length_ += length; |
| 711 } |
| 712 |
| 713 OVERLAPPED overlapped_; |
| 714 HANDLE handle_; |
| 715 HANDLE event_; |
| 716 char buffer_[kBufferSize]; |
| 717 uint8_t* data_; |
| 718 intptr_t data_length_; |
| 719 |
| 720 DISALLOW_ALLOCATION(); |
| 721 }; |
| 722 |
| 723 |
| 724 bool Process::Wait(intptr_t pid, |
| 725 intptr_t in, |
| 726 intptr_t out, |
| 727 intptr_t err, |
| 728 intptr_t exit_event, |
| 729 ProcessResult* result) { |
| 730 // Close input to the process right away. |
| 731 reinterpret_cast<FileHandle*>(in)->Close(); |
| 732 |
| 733 // All pipes created to the sub-process supports overlapped IO. |
| 734 FileHandle* stdout_handle = reinterpret_cast<FileHandle*>(out); |
| 735 ASSERT(stdout_handle->SupportsOverlappedIO()); |
| 736 FileHandle* stderr_handle = reinterpret_cast<FileHandle*>(err); |
| 737 ASSERT(stderr_handle->SupportsOverlappedIO()); |
| 738 FileHandle* exit_handle = reinterpret_cast<FileHandle*>(exit_event); |
| 739 ASSERT(exit_handle->SupportsOverlappedIO()); |
| 740 |
| 741 // Create three events for overlapped IO. These are created as already |
| 742 // signalled to ensure they have read called at least once. |
| 743 static const int kHandles = 3; |
| 744 HANDLE events[kHandles]; |
| 745 for (int i = 0; i < kHandles; i++) { |
| 746 events[i] = CreateEvent(NULL, FALSE, TRUE, NULL); |
| 747 } |
| 748 |
| 749 // Setup the structure for handling overlapped IO. |
| 750 OverlappedHandle oh[kHandles]; |
| 751 memset(&oh, 0, sizeof(oh)); |
| 752 oh[0].Init(stdout_handle->handle(), events[0]); |
| 753 oh[1].Init(stderr_handle->handle(), events[1]); |
| 754 oh[2].Init(exit_handle->handle(), events[2]); |
| 755 |
| 756 // Continue until all handles are closed. |
| 757 int alive = kHandles; |
| 758 while (alive > 0) { |
| 759 // Wait for event to become signalled. |
| 760 DWORD wait_result = WaitForMultipleObjects(alive, events, FALSE, INFINITE); |
| 761 |
| 762 // Find the handle signalled. |
| 763 int index = wait_result - WAIT_OBJECT_0; |
| 764 for (int i = 0; i < kHandles; i++) { |
| 765 if (oh[i].HasEvent(events[index])) { |
| 766 bool ok = oh[i].Read(); |
| 767 if (!ok) { |
| 768 if (GetLastError() == ERROR_BROKEN_PIPE) { |
| 769 oh[i].Close(); |
| 770 alive--; |
| 771 if (index < alive) { |
| 772 events[index] = events[alive]; |
| 773 } |
| 774 } else if (err != ERROR_IO_PENDING) { |
| 775 DWORD e = GetLastError(); |
| 776 oh[0].Destroy(); |
| 777 oh[1].Destroy(); |
| 778 oh[2].Destroy(); |
| 779 SetLastError(e); |
| 780 return false; |
| 781 } |
| 782 } |
| 783 break; |
| 784 } |
| 785 } |
| 786 } |
| 787 |
| 788 // All handles closed and all data read. |
| 789 result->SetStdoutData(oh[0].data(), oh[0].data_length()); |
| 790 result->SetStderrData(oh[1].data(), oh[1].data_length()); |
| 791 |
| 792 // Calculate the exit code. |
| 793 ASSERT(oh[2].data_length() == 8); |
| 794 uint32_t exit[2]; |
| 795 memcpy(&exit, oh[2].data(), sizeof(exit)); |
| 796 oh[2].FreeData(); |
| 797 intptr_t exit_code = exit[0]; |
| 798 intptr_t negative = exit[1]; |
| 799 if (negative) exit_code = -exit_code; |
| 800 result->set_exit_code(exit_code); |
| 801 return true; |
| 802 } |
| 803 |
| 804 |
| 645 bool Process::Kill(intptr_t id, int signal) { | 805 bool Process::Kill(intptr_t id, int signal) { |
| 646 USE(signal); // signal is not used on windows. | 806 USE(signal); // signal is not used on windows. |
| 647 HANDLE process_handle; | 807 HANDLE process_handle; |
| 648 HANDLE wait_handle; | 808 HANDLE wait_handle; |
| 649 HANDLE exit_pipe; | 809 HANDLE exit_pipe; |
| 650 bool success = ProcessInfoList::LookupProcess(id, | 810 bool success = ProcessInfoList::LookupProcess(id, |
| 651 &process_handle, | 811 &process_handle, |
| 652 &wait_handle, | 812 &wait_handle, |
| 653 &exit_pipe); | 813 &exit_pipe); |
| 654 // The process is already dead. | 814 // The process is already dead. |
| 655 if (!success) return false; | 815 if (!success) return false; |
| 656 BOOL result = TerminateProcess(process_handle, -1); | 816 BOOL result = TerminateProcess(process_handle, -1); |
| 657 return result ? true : false; | 817 return result ? true : false; |
| 658 } | 818 } |
| 659 | 819 |
| 660 | 820 |
| 661 void Process::TerminateExitCodeHandler() { | 821 void Process::TerminateExitCodeHandler() { |
| 662 // Nothing needs to be done on Windows. | 822 // Nothing needs to be done on Windows. |
| 663 } | 823 } |
| 664 | 824 |
| 665 | 825 |
| 666 intptr_t Process::CurrentProcessId() { | 826 intptr_t Process::CurrentProcessId() { |
| 667 return static_cast<intptr_t>(GetCurrentProcessId()); | 827 return static_cast<intptr_t>(GetCurrentProcessId()); |
| 668 } | 828 } |
| 669 | 829 |
| 670 } // namespace bin | 830 } // namespace bin |
| 671 } // namespace dart | 831 } // namespace dart |
| 672 | 832 |
| 673 #endif // defined(TARGET_OS_WINDOWS) | 833 #endif // defined(TARGET_OS_WINDOWS) |
| OLD | NEW |