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_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 BufferList: public BufferListBase { | |
| 646 public: | |
| 647 BufferList() : read_pending_(true) { } | |
| 648 | |
| 649 // Indicate that data has been read into the buffer provided to | |
| 650 // overlapped read. | |
| 651 void DataIsRead(intptr_t size) { | |
| 652 ASSERT(read_pending_ == true); | |
| 653 data_size_ += size; | |
| 654 free_size_ -= size; | |
| 655 ASSERT(free_size_ >= 0); | |
| 656 read_pending_ = false; | |
| 657 } | |
| 658 | |
| 659 // The access to the read buffer for overlapped read. | |
| 660 void GetReadBuffer(uint8_t** buffer, intptr_t* size) { | |
| 661 ASSERT(!read_pending_); | |
| 662 if (free_size_ == 0) Allocate(); | |
| 663 ASSERT(free_size_ > 0); | |
| 664 ASSERT(free_size_ <= kBufferSize); | |
| 665 *buffer = FreeSpaceAddress(); | |
| 666 *size = free_size_; | |
| 667 read_pending_ = true; | |
| 668 } | |
| 669 | |
| 670 intptr_t GetDataSize() { | |
| 671 return data_size_; | |
| 672 } | |
| 673 | |
| 674 uint8_t* GetFirstDataBuffer() { | |
| 675 ASSERT(head_ != NULL); | |
| 676 ASSERT(head_ == tail_); | |
| 677 ASSERT(data_size_ <= kBufferSize); | |
| 678 return head_->data_; | |
| 679 } | |
| 680 | |
| 681 void FreeDataBuffer() { | |
| 682 Free(); | |
| 683 } | |
| 684 | |
| 685 private: | |
| 686 bool read_pending_; | |
| 687 }; | |
| 688 | |
| 689 | |
| 690 class OverlappedHandle { | |
| 691 public: | |
| 692 void Init(HANDLE handle, HANDLE event) { | |
| 693 handle_ = handle; | |
| 694 event_ = event; | |
| 695 ClearOverlapped(); | |
| 696 } | |
| 697 | |
| 698 bool HasEvent(HANDLE event) { | |
| 699 return event_ == event; | |
| 700 } | |
| 701 | |
| 702 bool Read() { | |
| 703 // Get the data read as a result of a completed overlapped operation. | |
| 704 if (overlapped_.InternalHigh > 0) { | |
| 705 buffer_.DataIsRead(overlapped_.InternalHigh); | |
| 706 } else { | |
| 707 buffer_.DataIsRead(0); | |
| 708 } | |
| 709 | |
| 710 // Keep reading until error or pending operation. | |
| 711 while (true) { | |
| 712 ClearOverlapped(); | |
| 713 uint8_t* buffer; | |
| 714 intptr_t buffer_size; | |
| 715 buffer_.GetReadBuffer(&buffer, &buffer_size); | |
| 716 BOOL ok = ReadFile(handle_, buffer, buffer_size, NULL, &overlapped_); | |
| 717 if (!ok) return GetLastError() == ERROR_IO_PENDING; | |
| 718 buffer_.DataIsRead(overlapped_.InternalHigh); | |
| 719 } | |
| 720 } | |
| 721 | |
| 722 Dart_Handle GetData() { | |
| 723 return buffer_.GetData(); | |
| 724 } | |
| 725 | |
| 726 intptr_t GetDataSize() { | |
| 727 return buffer_.GetDataSize(); | |
| 728 } | |
| 729 | |
| 730 uint8_t* GetFirstDataBuffer() { | |
| 731 return buffer_.GetFirstDataBuffer(); | |
| 732 } | |
| 733 | |
| 734 void FreeDataBuffer() { | |
| 735 return buffer_.FreeDataBuffer(); | |
| 736 } | |
| 737 | |
| 738 void Close() { | |
| 739 CloseHandle(handle_); | |
| 740 CloseHandle(event_); | |
| 741 handle_ = INVALID_HANDLE_VALUE; | |
| 742 overlapped_.hEvent = INVALID_HANDLE_VALUE; | |
| 743 } | |
| 744 | |
| 745 private: | |
| 746 void ClearOverlapped() { | |
| 747 memset(&overlapped_, 0, sizeof(overlapped_)); | |
| 748 overlapped_.hEvent = event_; | |
| 749 } | |
| 750 | |
| 751 OVERLAPPED overlapped_; | |
| 752 HANDLE handle_; | |
| 753 HANDLE event_; | |
| 754 BufferList buffer_; | |
| 755 | |
| 756 DISALLOW_ALLOCATION(); | |
| 757 }; | |
| 758 | |
| 759 | |
| 760 bool Process::Wait(intptr_t pid, | |
| 761 intptr_t in, | |
| 762 intptr_t out, | |
| 763 intptr_t err, | |
| 764 intptr_t exit_event, | |
| 765 ProcessResult* result) { | |
| 766 // Close input to the process right away. | |
| 767 reinterpret_cast<FileHandle*>(in)->Close(); | |
| 768 | |
| 769 // All pipes created to the sub-process support overlapped IO. | |
| 770 FileHandle* stdout_handle = reinterpret_cast<FileHandle*>(out); | |
| 771 ASSERT(stdout_handle->SupportsOverlappedIO()); | |
| 772 FileHandle* stderr_handle = reinterpret_cast<FileHandle*>(err); | |
| 773 ASSERT(stderr_handle->SupportsOverlappedIO()); | |
| 774 FileHandle* exit_handle = reinterpret_cast<FileHandle*>(exit_event); | |
| 775 ASSERT(exit_handle->SupportsOverlappedIO()); | |
| 776 | |
| 777 // Create three events for overlapped IO. These are created as already | |
| 778 // signalled to ensure they have read called at least once. | |
| 779 static const int kHandles = 3; | |
| 780 HANDLE events[kHandles]; | |
| 781 for (int i = 0; i < kHandles; i++) { | |
| 782 events[i] = CreateEvent(NULL, FALSE, TRUE, NULL); | |
| 783 } | |
| 784 | |
| 785 // Setup the structure for handling overlapped IO. | |
| 786 OverlappedHandle oh[kHandles]; | |
|
Anders Johnsen
2013/08/19 05:27:59
Best variable name ever! :)
| |
| 787 oh[0].Init(stdout_handle->handle(), events[0]); | |
| 788 oh[1].Init(stderr_handle->handle(), events[1]); | |
| 789 oh[2].Init(exit_handle->handle(), events[2]); | |
| 790 | |
| 791 // Continue until all handles are closed. | |
| 792 int alive = kHandles; | |
| 793 while (alive > 0) { | |
| 794 // Blocking call waiting for events from the child process. | |
| 795 DWORD wait_result = WaitForMultipleObjects(alive, events, FALSE, INFINITE); | |
| 796 | |
| 797 // Find the handle signalled. | |
| 798 int index = wait_result - WAIT_OBJECT_0; | |
| 799 for (int i = 0; i < kHandles; i++) { | |
| 800 if (oh[i].HasEvent(events[index])) { | |
| 801 bool ok = oh[i].Read(); | |
| 802 if (!ok) { | |
| 803 if (GetLastError() == ERROR_BROKEN_PIPE) { | |
| 804 oh[i].Close(); | |
| 805 alive--; | |
| 806 if (index < alive) { | |
| 807 events[index] = events[alive]; | |
| 808 } | |
| 809 } else if (err != ERROR_IO_PENDING) { | |
| 810 DWORD e = GetLastError(); | |
| 811 oh[0].Close(); | |
| 812 oh[1].Close(); | |
| 813 oh[2].Close(); | |
| 814 SetLastError(e); | |
| 815 return false; | |
| 816 } | |
| 817 } | |
| 818 break; | |
| 819 } | |
| 820 } | |
| 821 } | |
| 822 | |
| 823 // All handles closed and all data read. | |
| 824 result->set_stdout_data(oh[0].GetData()); | |
| 825 result->set_stderr_data(oh[1].GetData()); | |
| 826 | |
| 827 // Calculate the exit code. | |
| 828 ASSERT(oh[2].GetDataSize() == 8); | |
| 829 uint32_t exit[2]; | |
| 830 memcpy(&exit, oh[2].GetFirstDataBuffer(), sizeof(exit)); | |
| 831 oh[2].FreeDataBuffer(); | |
| 832 intptr_t exit_code = exit[0]; | |
| 833 intptr_t negative = exit[1]; | |
| 834 if (negative) exit_code = -exit_code; | |
| 835 result->set_exit_code(exit_code); | |
| 836 return true; | |
| 837 } | |
| 838 | |
| 839 | |
| 645 bool Process::Kill(intptr_t id, int signal) { | 840 bool Process::Kill(intptr_t id, int signal) { |
| 646 USE(signal); // signal is not used on windows. | 841 USE(signal); // signal is not used on windows. |
| 647 HANDLE process_handle; | 842 HANDLE process_handle; |
| 648 HANDLE wait_handle; | 843 HANDLE wait_handle; |
| 649 HANDLE exit_pipe; | 844 HANDLE exit_pipe; |
| 650 bool success = ProcessInfoList::LookupProcess(id, | 845 bool success = ProcessInfoList::LookupProcess(id, |
| 651 &process_handle, | 846 &process_handle, |
| 652 &wait_handle, | 847 &wait_handle, |
| 653 &exit_pipe); | 848 &exit_pipe); |
| 654 // The process is already dead. | 849 // The process is already dead. |
| 655 if (!success) return false; | 850 if (!success) return false; |
| 656 BOOL result = TerminateProcess(process_handle, -1); | 851 BOOL result = TerminateProcess(process_handle, -1); |
| 657 return result ? true : false; | 852 return result ? true : false; |
| 658 } | 853 } |
| 659 | 854 |
| 660 | 855 |
| 661 void Process::TerminateExitCodeHandler() { | 856 void Process::TerminateExitCodeHandler() { |
| 662 // Nothing needs to be done on Windows. | 857 // Nothing needs to be done on Windows. |
| 663 } | 858 } |
| 664 | 859 |
| 665 | 860 |
| 666 intptr_t Process::CurrentProcessId() { | 861 intptr_t Process::CurrentProcessId() { |
| 667 return static_cast<intptr_t>(GetCurrentProcessId()); | 862 return static_cast<intptr_t>(GetCurrentProcessId()); |
| 668 } | 863 } |
| 669 | 864 |
| 670 } // namespace bin | 865 } // namespace bin |
| 671 } // namespace dart | 866 } // namespace dart |
| 672 | 867 |
| 673 #endif // defined(TARGET_OS_WINDOWS) | 868 #endif // defined(TARGET_OS_WINDOWS) |
| OLD | NEW |