| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 "bin/eventhandler.h" | 8 #include "bin/eventhandler.h" |
| 9 | 9 |
| 10 #include <process.h> // NOLINT | |
| 11 #include <winsock2.h> // NOLINT | 10 #include <winsock2.h> // NOLINT |
| 12 #include <ws2tcpip.h> // NOLINT | 11 #include <ws2tcpip.h> // NOLINT |
| 13 #include <mswsock.h> // NOLINT | 12 #include <mswsock.h> // NOLINT |
| 14 #include <io.h> // NOLINT | 13 #include <io.h> // NOLINT |
| 15 #include <fcntl.h> // NOLINT | 14 #include <fcntl.h> // NOLINT |
| 16 | 15 |
| 17 #include "bin/builtin.h" | 16 #include "bin/builtin.h" |
| 18 #include "bin/dartutils.h" | 17 #include "bin/dartutils.h" |
| 19 #include "bin/log.h" | 18 #include "bin/log.h" |
| 20 #include "bin/socket.h" | 19 #include "bin/socket.h" |
| 21 #include "bin/utils.h" | 20 #include "bin/utils.h" |
| 22 #include "platform/thread.h" | 21 #include "vm/thread.h" |
| 23 | 22 |
| 24 | 23 |
| 25 namespace dart { | 24 namespace dart { |
| 26 namespace bin { | 25 namespace bin { |
| 27 | 26 |
| 28 static const int kBufferSize = 64 * 1024; | 27 static const int kBufferSize = 64 * 1024; |
| 29 static const int kStdOverlappedBufferSize = 16 * 1024; | 28 static const int kStdOverlappedBufferSize = 16 * 1024; |
| 30 | 29 |
| 31 static const int kInfinityTimeout = -1; | 30 static const int kInfinityTimeout = -1; |
| 32 static const int kTimeoutId = -1; | 31 static const int kTimeoutId = -1; |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 Handle::Handle(HANDLE handle) | 99 Handle::Handle(HANDLE handle) |
| 101 : handle_(reinterpret_cast<HANDLE>(handle)), | 100 : handle_(reinterpret_cast<HANDLE>(handle)), |
| 102 port_(0), | 101 port_(0), |
| 103 mask_(0), | 102 mask_(0), |
| 104 completion_port_(INVALID_HANDLE_VALUE), | 103 completion_port_(INVALID_HANDLE_VALUE), |
| 105 event_handler_(NULL), | 104 event_handler_(NULL), |
| 106 data_ready_(NULL), | 105 data_ready_(NULL), |
| 107 pending_read_(NULL), | 106 pending_read_(NULL), |
| 108 pending_write_(NULL), | 107 pending_write_(NULL), |
| 109 last_error_(NOERROR), | 108 last_error_(NOERROR), |
| 110 thread_wrote_(0), | |
| 111 flags_(0) { | 109 flags_(0) { |
| 112 InitializeCriticalSection(&cs_); | 110 InitializeCriticalSection(&cs_); |
| 113 } | 111 } |
| 114 | 112 |
| 115 | 113 |
| 116 Handle::Handle(HANDLE handle, Dart_Port port) | 114 Handle::Handle(HANDLE handle, Dart_Port port) |
| 117 : handle_(reinterpret_cast<HANDLE>(handle)), | 115 : handle_(reinterpret_cast<HANDLE>(handle)), |
| 118 port_(port), | 116 port_(port), |
| 119 mask_(0), | 117 mask_(0), |
| 120 completion_port_(INVALID_HANDLE_VALUE), | 118 completion_port_(INVALID_HANDLE_VALUE), |
| 121 event_handler_(NULL), | 119 event_handler_(NULL), |
| 122 data_ready_(NULL), | 120 data_ready_(NULL), |
| 123 pending_read_(NULL), | 121 pending_read_(NULL), |
| 124 pending_write_(NULL), | 122 pending_write_(NULL), |
| 125 last_error_(NOERROR), | 123 last_error_(NOERROR), |
| 126 thread_wrote_(0), | |
| 127 flags_(0) { | 124 flags_(0) { |
| 128 InitializeCriticalSection(&cs_); | 125 InitializeCriticalSection(&cs_); |
| 129 } | 126 } |
| 130 | 127 |
| 131 | 128 |
| 132 Handle::~Handle() { | 129 Handle::~Handle() { |
| 133 DeleteCriticalSection(&cs_); | 130 DeleteCriticalSection(&cs_); |
| 134 } | 131 } |
| 135 | 132 |
| 136 | 133 |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 204 | 201 |
| 205 void Handle::WriteComplete(OverlappedBuffer* buffer) { | 202 void Handle::WriteComplete(OverlappedBuffer* buffer) { |
| 206 ScopedLock lock(this); | 203 ScopedLock lock(this); |
| 207 // Currently only one outstanding write at the time. | 204 // Currently only one outstanding write at the time. |
| 208 ASSERT(pending_write_ == buffer); | 205 ASSERT(pending_write_ == buffer); |
| 209 OverlappedBuffer::DisposeBuffer(buffer); | 206 OverlappedBuffer::DisposeBuffer(buffer); |
| 210 pending_write_ = NULL; | 207 pending_write_ = NULL; |
| 211 } | 208 } |
| 212 | 209 |
| 213 | 210 |
| 214 static unsigned int __stdcall ReadFileThread(void* args) { | 211 static void ReadFileThread(uword args) { |
| 215 Handle* handle = reinterpret_cast<Handle*>(args); | 212 Handle* handle = reinterpret_cast<Handle*>(args); |
| 216 handle->ReadSyncCompleteAsync(); | 213 handle->ReadSyncCompleteAsync(); |
| 217 return 0; | |
| 218 } | 214 } |
| 219 | 215 |
| 220 | 216 |
| 221 void Handle::ReadSyncCompleteAsync() { | 217 void Handle::ReadSyncCompleteAsync() { |
| 222 ASSERT(pending_read_ != NULL); | 218 ASSERT(pending_read_ != NULL); |
| 223 ASSERT(pending_read_->GetBufferSize() >= kStdOverlappedBufferSize); | 219 ASSERT(pending_read_->GetBufferSize() >= kStdOverlappedBufferSize); |
| 224 | 220 |
| 225 DWORD buffer_size = pending_read_->GetBufferSize(); | 221 DWORD buffer_size = pending_read_->GetBufferSize(); |
| 226 if (GetFileType(handle_) == FILE_TYPE_CHAR) { | 222 if (GetFileType(handle_) == FILE_TYPE_CHAR) { |
| 227 buffer_size = kStdOverlappedBufferSize; | 223 buffer_size = kStdOverlappedBufferSize; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 266 // Completing asynchronously. | 262 // Completing asynchronously. |
| 267 pending_read_ = buffer; | 263 pending_read_ = buffer; |
| 268 return true; | 264 return true; |
| 269 } | 265 } |
| 270 OverlappedBuffer::DisposeBuffer(buffer); | 266 OverlappedBuffer::DisposeBuffer(buffer); |
| 271 HandleIssueError(); | 267 HandleIssueError(); |
| 272 return false; | 268 return false; |
| 273 } else { | 269 } else { |
| 274 // Completing asynchronously through thread. | 270 // Completing asynchronously through thread. |
| 275 pending_read_ = buffer; | 271 pending_read_ = buffer; |
| 276 uint32_t tid; | 272 int result = dart::Thread::Start(ReadFileThread, |
| 277 uintptr_t thread_handle = | 273 reinterpret_cast<uword>(this)); |
| 278 _beginthreadex(NULL, 32 * 1024, ReadFileThread, this, 0, &tid); | 274 if (result != 0) { |
| 279 if (thread_handle == -1) { | 275 FATAL("Failed to start read file thread %d", result); |
| 280 FATAL("Failed to start read file thread"); | |
| 281 } | 276 } |
| 282 return true; | 277 return true; |
| 283 } | 278 } |
| 284 } | 279 } |
| 285 | 280 |
| 286 | 281 |
| 287 bool Handle::IssueWrite() { | 282 bool Handle::IssueWrite() { |
| 288 ScopedLock lock(this); | 283 ScopedLock lock(this); |
| 289 ASSERT(type_ != kListenSocket); | 284 ASSERT(type_ != kListenSocket); |
| 290 ASSERT(completion_port_ != INVALID_HANDLE_VALUE); | 285 ASSERT(completion_port_ != INVALID_HANDLE_VALUE); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 326 CreateCompletionPort(event_handler_->completion_port()); | 321 CreateCompletionPort(event_handler_->completion_port()); |
| 327 } | 322 } |
| 328 } | 323 } |
| 329 | 324 |
| 330 | 325 |
| 331 bool FileHandle::IsClosed() { | 326 bool FileHandle::IsClosed() { |
| 332 return IsClosing() && !HasPendingRead() && !HasPendingWrite(); | 327 return IsClosing() && !HasPendingRead() && !HasPendingWrite(); |
| 333 } | 328 } |
| 334 | 329 |
| 335 | 330 |
| 336 void FileHandle::DoClose() { | |
| 337 if (handle_ == GetStdHandle(STD_OUTPUT_HANDLE)) { | |
| 338 int fd = _open("NUL", _O_WRONLY); | |
| 339 ASSERT(fd >= 0); | |
| 340 _dup2(fd, _fileno(stdout)); | |
| 341 close(fd); | |
| 342 } else { | |
| 343 Handle::DoClose(); | |
| 344 } | |
| 345 } | |
| 346 | |
| 347 | |
| 348 void DirectoryWatchHandle::EnsureInitialized( | 331 void DirectoryWatchHandle::EnsureInitialized( |
| 349 EventHandlerImplementation* event_handler) { | 332 EventHandlerImplementation* event_handler) { |
| 350 ScopedLock lock(this); | 333 ScopedLock lock(this); |
| 351 event_handler_ = event_handler; | 334 event_handler_ = event_handler; |
| 352 if (completion_port_ == INVALID_HANDLE_VALUE) { | 335 if (completion_port_ == INVALID_HANDLE_VALUE) { |
| 353 CreateCompletionPort(event_handler_->completion_port()); | 336 CreateCompletionPort(event_handler_->completion_port()); |
| 354 } | 337 } |
| 355 } | 338 } |
| 356 | 339 |
| 357 | 340 |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 553 if (data_ready_ == NULL) return 0; | 536 if (data_ready_ == NULL) return 0; |
| 554 num_bytes = data_ready_->Read(buffer, num_bytes); | 537 num_bytes = data_ready_->Read(buffer, num_bytes); |
| 555 if (data_ready_->IsEmpty()) { | 538 if (data_ready_->IsEmpty()) { |
| 556 OverlappedBuffer::DisposeBuffer(data_ready_); | 539 OverlappedBuffer::DisposeBuffer(data_ready_); |
| 557 data_ready_ = NULL; | 540 data_ready_ = NULL; |
| 558 } | 541 } |
| 559 return num_bytes; | 542 return num_bytes; |
| 560 } | 543 } |
| 561 | 544 |
| 562 | 545 |
| 563 static unsigned int __stdcall WriteFileThread(void* args) { | 546 int Handle::Write(const void* buffer, int num_bytes) { |
| 564 Handle* handle = reinterpret_cast<Handle*>(args); | 547 ScopedLock lock(this); |
| 565 handle->WriteSyncCompleteAsync(); | 548 if (pending_write_ != NULL) return 0; |
| 566 return 0; | 549 if (num_bytes > kBufferSize) num_bytes = kBufferSize; |
| 550 ASSERT(SupportsOverlappedIO()); |
| 551 if (completion_port_ == INVALID_HANDLE_VALUE) return 0; |
| 552 pending_write_ = OverlappedBuffer::AllocateWriteBuffer(num_bytes); |
| 553 pending_write_->Write(buffer, num_bytes); |
| 554 if (!IssueWrite()) return -1; |
| 555 return num_bytes; |
| 567 } | 556 } |
| 568 | 557 |
| 569 | 558 |
| 570 void Handle::WriteSyncCompleteAsync() { | 559 static void WriteFileThread(uword args) { |
| 560 StdHandle* handle = reinterpret_cast<StdHandle*>(args); |
| 561 handle->RunWriteLoop(); |
| 562 } |
| 563 |
| 564 |
| 565 void StdHandle::RunWriteLoop() { |
| 566 write_monitor_->Enter(); |
| 567 write_thread_running_ = true; |
| 568 // Notify we have started. |
| 569 write_monitor_->Notify(); |
| 570 |
| 571 while (write_thread_running_) { |
| 572 write_monitor_->Wait(Monitor::kNoTimeout); |
| 573 if (pending_write_ != NULL) { |
| 574 // We woke up and had a pending write. Execute it. |
| 575 WriteSyncCompleteAsync(); |
| 576 } |
| 577 } |
| 578 |
| 579 write_thread_exists_ = false; |
| 580 write_monitor_->Notify(); |
| 581 write_monitor_->Exit(); |
| 582 } |
| 583 |
| 584 |
| 585 void StdHandle::WriteSyncCompleteAsync() { |
| 571 ASSERT(pending_write_ != NULL); | 586 ASSERT(pending_write_ != NULL); |
| 572 | 587 |
| 573 DWORD bytes_written = -1; | 588 DWORD bytes_written = -1; |
| 574 BOOL ok = WriteFile(handle_, | 589 BOOL ok = WriteFile(handle_, |
| 575 pending_write_->GetBufferStart(), | 590 pending_write_->GetBufferStart(), |
| 576 pending_write_->GetBufferSize(), | 591 pending_write_->GetBufferSize(), |
| 577 &bytes_written, | 592 &bytes_written, |
| 578 NULL); | 593 NULL); |
| 579 if (!ok) { | 594 if (!ok) { |
| 580 if (GetLastError() != ERROR_BROKEN_PIPE) { | 595 if (GetLastError() != ERROR_BROKEN_PIPE) { |
| 581 Log::PrintErr("WriteFile failed %d\n", GetLastError()); | 596 Log::PrintErr("WriteFile failed %d\n", GetLastError()); |
| 582 } | 597 } |
| 583 bytes_written = 0; | 598 bytes_written = 0; |
| 584 } | 599 } |
| 585 thread_wrote_ += bytes_written; | 600 thread_wrote_ += bytes_written; |
| 586 OVERLAPPED* overlapped = pending_write_->GetCleanOverlapped(); | 601 OVERLAPPED* overlapped = pending_write_->GetCleanOverlapped(); |
| 587 ok = PostQueuedCompletionStatus(event_handler_->completion_port(), | 602 ok = PostQueuedCompletionStatus(event_handler_->completion_port(), |
| 588 bytes_written, | 603 bytes_written, |
| 589 reinterpret_cast<ULONG_PTR>(this), | 604 reinterpret_cast<ULONG_PTR>(this), |
| 590 overlapped); | 605 overlapped); |
| 591 if (!ok) { | 606 if (!ok) { |
| 592 FATAL("PostQueuedCompletionStatus failed"); | 607 FATAL("PostQueuedCompletionStatus failed"); |
| 593 } | 608 } |
| 594 } | 609 } |
| 595 | 610 |
| 596 | 611 int StdHandle::Write(const void* buffer, int num_bytes) { |
| 597 int Handle::Write(const void* buffer, int num_bytes) { | |
| 598 ScopedLock lock(this); | 612 ScopedLock lock(this); |
| 599 if (pending_write_ != NULL) return 0; | 613 if (pending_write_ != NULL) return 0; |
| 600 if (num_bytes > kBufferSize) num_bytes = kBufferSize; | 614 if (num_bytes > kBufferSize) num_bytes = kBufferSize; |
| 601 if (SupportsOverlappedIO()) { | 615 // In the case of stdout and stderr, OverlappedIO is not supported. |
| 602 if (completion_port_ == INVALID_HANDLE_VALUE) return 0; | 616 // Here we'll instead use a thread, to make it async. |
| 603 pending_write_ = OverlappedBuffer::AllocateWriteBuffer(num_bytes); | 617 // This code is actually never exposed to the user, as stdout and stderr is |
| 604 pending_write_->Write(buffer, num_bytes); | 618 // not available as a RawSocket, but only wrapped in a Socket. |
| 605 if (!IssueWrite()) return -1; | 619 // Note that we return '0', unless a thread have already completed a write. |
| 620 MonitorLocker locker(write_monitor_); |
| 621 if (thread_wrote_ > 0) { |
| 622 if (num_bytes > thread_wrote_) num_bytes = thread_wrote_; |
| 623 thread_wrote_ -= num_bytes; |
| 606 return num_bytes; | 624 return num_bytes; |
| 625 } |
| 626 if (!write_thread_exists_) { |
| 627 write_thread_exists_ = true; |
| 628 int result = dart::Thread::Start(WriteFileThread, |
| 629 reinterpret_cast<uword>(this)); |
| 630 if (result != 0) { |
| 631 FATAL("Failed to start write file thread %d", result); |
| 632 } |
| 633 while (!write_thread_running_) { |
| 634 // Wait until we the thread is running. |
| 635 locker.Wait(Monitor::kNoTimeout); |
| 636 } |
| 637 } |
| 638 // Create buffer and notify thread about the new handle. |
| 639 pending_write_ = OverlappedBuffer::AllocateWriteBuffer(num_bytes); |
| 640 pending_write_->Write(buffer, num_bytes); |
| 641 locker.Notify(); |
| 642 return 0; |
| 643 } |
| 644 |
| 645 |
| 646 void StdHandle::DoClose() { |
| 647 MonitorLocker locker(write_monitor_); |
| 648 if (write_thread_exists_) { |
| 649 write_thread_running_ = false; |
| 650 locker.Notify(); |
| 651 while (write_thread_exists_) { |
| 652 locker.Wait(Monitor::kNoTimeout); |
| 653 } |
| 654 } |
| 655 if (handle_ == GetStdHandle(STD_OUTPUT_HANDLE)) { |
| 656 int fd = _open("NUL", _O_WRONLY); |
| 657 ASSERT(fd >= 0); |
| 658 _dup2(fd, _fileno(stdout)); |
| 659 close(fd); |
| 607 } else { | 660 } else { |
| 608 // In the case of stdout and stderr, OverlappedIO is not supported. | 661 Handle::DoClose(); |
| 609 // Here we'll instead spawn a new thread for each write, to make it async. | |
| 610 // This code is actually never exposed to the user, as stdout and stderr is | |
| 611 // not available as a RawSocket, but only wrapped in a Socket. | |
| 612 // Note that we return '0', unless a thread have already completed a write. | |
| 613 // TODO(ajohnsen): Don't spawn a new thread per write. Issue 13541. | |
| 614 if (thread_wrote_ > 0) { | |
| 615 if (num_bytes > thread_wrote_) num_bytes = thread_wrote_; | |
| 616 thread_wrote_ -= num_bytes; | |
| 617 return num_bytes; | |
| 618 } | |
| 619 pending_write_ = OverlappedBuffer::AllocateWriteBuffer(num_bytes); | |
| 620 pending_write_->Write(buffer, num_bytes); | |
| 621 // Completing asynchronously through thread. | |
| 622 uint32_t tid; | |
| 623 uintptr_t thread_handle = | |
| 624 _beginthreadex(NULL, 32 * 1024, WriteFileThread, this, 0, &tid); | |
| 625 if (thread_handle == -1) { | |
| 626 FATAL("Failed to start write file thread"); | |
| 627 } | |
| 628 return 0; | |
| 629 } | 662 } |
| 630 } | 663 } |
| 631 | 664 |
| 632 | 665 |
| 633 bool ClientSocket::LoadDisconnectEx() { | 666 bool ClientSocket::LoadDisconnectEx() { |
| 634 // Load the DisconnectEx function into memory using WSAIoctl. | 667 // Load the DisconnectEx function into memory using WSAIoctl. |
| 635 GUID guid_disconnect_ex = WSAID_DISCONNECTEX; | 668 GUID guid_disconnect_ex = WSAID_DISCONNECTEX; |
| 636 DWORD bytes; | 669 DWORD bytes; |
| 637 int status = WSAIoctl(socket(), | 670 int status = WSAIoctl(socket(), |
| 638 SIO_GET_EXTENSION_FUNCTION_POINTER, | 671 SIO_GET_EXTENSION_FUNCTION_POINTER, |
| (...skipping 460 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1099 | 1132 |
| 1100 | 1133 |
| 1101 void EventHandlerImplementation::Shutdown() { | 1134 void EventHandlerImplementation::Shutdown() { |
| 1102 SendData(kShutdownId, 0, 0); | 1135 SendData(kShutdownId, 0, 0); |
| 1103 } | 1136 } |
| 1104 | 1137 |
| 1105 } // namespace bin | 1138 } // namespace bin |
| 1106 } // namespace dart | 1139 } // namespace dart |
| 1107 | 1140 |
| 1108 #endif // defined(TARGET_OS_WINDOWS) | 1141 #endif // defined(TARGET_OS_WINDOWS) |
| OLD | NEW |