Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(32)

Side by Side Diff: runtime/bin/eventhandler_win.cc

Issue 25631005: Reuse thread when writing stdout/stderr on Windows. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Make the thread a part of the StdHandle. Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/bin/eventhandler_win.h ('k') | runtime/bin/socket_win.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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)
OLDNEW
« no previous file with comments | « runtime/bin/eventhandler_win.h ('k') | runtime/bin/socket_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698