| Index: runtime/bin/eventhandler_win.cc
 | 
| diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc
 | 
| index e961581be4827226a2fc72e8be21be5d325150ac..a6c16a6480f44e781d4f5de0fa485313ec5389f9 100644
 | 
| --- a/runtime/bin/eventhandler_win.cc
 | 
| +++ b/runtime/bin/eventhandler_win.cc
 | 
| @@ -156,7 +156,15 @@ void Handle::Close() {
 | 
|      // If the handle uses synchronous I/O (e.g. stdin), cancel any pending
 | 
|      // operation before closing the handle, so the read thread is not blocked.
 | 
|      BOOL result = CancelIoEx(handle_, NULL);
 | 
| -    ASSERT(result || (GetLastError() == ERROR_NOT_FOUND));
 | 
| +// The Dart code 'stdin.listen(() {}).cancel()' causes this assert to be
 | 
| +// triggered on Windows 7, but not on Windows 10.
 | 
| +#if defined(DEBUG)
 | 
| +    if (IsWindows10OrGreater()) {
 | 
| +      ASSERT(result || (GetLastError() == ERROR_NOT_FOUND));
 | 
| +    }
 | 
| +#else
 | 
| +    USE(result);
 | 
| +#endif
 | 
|    }
 | 
|    if (!IsClosing()) {
 | 
|      // Close the socket and set the closing state. This close method can be
 | 
| @@ -753,6 +761,18 @@ intptr_t Handle::SendTo(const void* buffer,
 | 
|  }
 | 
|  
 | 
|  
 | 
| +Mutex* StdHandle::stdin_mutex_ = new Mutex();
 | 
| +StdHandle* StdHandle::stdin_ = NULL;
 | 
| +
 | 
| +StdHandle* StdHandle::Stdin(HANDLE handle) {
 | 
| +  MutexLocker ml(stdin_mutex_);
 | 
| +  if (stdin_ == NULL) {
 | 
| +    stdin_ = new StdHandle(handle);
 | 
| +  }
 | 
| +  return stdin_;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  static void WriteFileThread(uword args) {
 | 
|    StdHandle* handle = reinterpret_cast<StdHandle*>(args);
 | 
|    handle->RunWriteLoop();
 | 
| @@ -845,19 +865,24 @@ intptr_t StdHandle::Write(const void* buffer, intptr_t num_bytes) {
 | 
|  
 | 
|  
 | 
|  void StdHandle::DoClose() {
 | 
| -  MonitorLocker ml(monitor_);
 | 
| -  if (write_thread_exists_) {
 | 
| -    write_thread_running_ = false;
 | 
| -    ml.Notify();
 | 
| -    while (write_thread_exists_) {
 | 
| -      ml.Wait(Monitor::kNoTimeout);
 | 
| +  {
 | 
| +    MonitorLocker ml(monitor_);
 | 
| +    if (write_thread_exists_) {
 | 
| +      write_thread_running_ = false;
 | 
| +      ml.Notify();
 | 
| +      while (write_thread_exists_) {
 | 
| +        ml.Wait(Monitor::kNoTimeout);
 | 
| +      }
 | 
| +      // Join the thread.
 | 
| +      DWORD res = WaitForSingleObject(thread_handle_, INFINITE);
 | 
| +      CloseHandle(thread_handle_);
 | 
| +      ASSERT(res == WAIT_OBJECT_0);
 | 
|      }
 | 
| -    // Join the thread.
 | 
| -    DWORD res = WaitForSingleObject(thread_handle_, INFINITE);
 | 
| -    CloseHandle(thread_handle_);
 | 
| -    ASSERT(res == WAIT_OBJECT_0);
 | 
| +    Handle::DoClose();
 | 
|    }
 | 
| -  Handle::DoClose();
 | 
| +  MutexLocker ml(stdin_mutex_);
 | 
| +  stdin_->Release();
 | 
| +  StdHandle::stdin_ = NULL;
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -1512,7 +1537,6 @@ void EventHandlerImplementation::EventHandlerEntry(uword args) {
 | 
|      }
 | 
|      handler_impl->HandleCompletionOrInterrupt(ok, bytes, key, overlapped);
 | 
|    }
 | 
| -#endif
 | 
|  
 | 
|    // The eventhandler thread is going down so there should be no more live
 | 
|    // Handles or Sockets.
 | 
| @@ -1520,9 +1544,13 @@ void EventHandlerImplementation::EventHandlerEntry(uword args) {
 | 
|    //     ReferenceCounted<Handle>::instances() == 0;
 | 
|    // However, we cannot at the moment. See the TODO on:
 | 
|    //     ClientSocket::IssueDisconnect()
 | 
| +  // Furthermore, if the Dart program references stdin, but does not
 | 
| +  // explicitly close it, then the StdHandle for it will be leaked to here.
 | 
| +  const intptr_t stdin_leaked = (StdHandle::StdinPtr() == NULL) ? 0 : 1;
 | 
|    DEBUG_ASSERT(ReferenceCounted<Handle>::instances() ==
 | 
| -               ClientSocket::disconnecting());
 | 
| +               ClientSocket::disconnecting() + stdin_leaked);
 | 
|    DEBUG_ASSERT(ReferenceCounted<Socket>::instances() == 0);
 | 
| +#endif  // defined(DEBUG)
 | 
|    handler->NotifyShutdownDone();
 | 
|  }
 | 
|  
 | 
| 
 |