[vm/io,win] Avoid recursive locking in EventHandler

Fixes https://github.com/dart-lang/sdk/issues/35118

TEST=standalone/io

Cq-Include-Trybots: luci.dart.try:vm-win-debug-x64-try,pkg-win-release-try,analyzer-win-release-try,vm-win-release-x64-try
Change-Id: I3d447a835a618b05507f27ce55d57f501da441ff
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/378922
Commit-Queue: Slava Egorov <vegorov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc
index 2ade87b..a42373a 100644
--- a/runtime/bin/eventhandler_win.cc
+++ b/runtime/bin/eventhandler_win.cc
@@ -210,6 +210,10 @@
 
 void Handle::Close() {
   MonitorLocker ml(&monitor_);
+  CloseLocked(&ml);
+}
+
+void Handle::CloseLocked(MonitorLocker* ml) {
   if (!supports_overlapped_io()) {
     // 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.
@@ -221,12 +225,12 @@
     // called again if this socket has pending IO operations in flight.
     MarkClosing();
     // Perform handle type specific closing.
-    DoClose();
+    DoCloseLocked(ml);
   }
   ASSERT(IsHandleClosed());
 }
 
-void Handle::DoClose() {
+void Handle::DoCloseLocked(MonitorLocker* ml) {
   if (!IsHandleClosed()) {
     CloseHandle(handle_);
     handle_ = INVALID_HANDLE_VALUE;
@@ -335,7 +339,7 @@
   NotifyReadThreadFinished();
 }
 
-bool Handle::IssueRead() {
+bool Handle::IssueReadLocked(MonitorLocker* ml) {
   ASSERT(type_ != kListenSocket);
   ASSERT(!HasPendingRead());
   auto buffer = OverlappedBuffer::AllocateReadBuffer(this, kBufferSize);
@@ -374,12 +378,12 @@
   }
 }
 
-bool Handle::IssueRecvFrom() {
+bool Handle::IssueRecvFromLocked(MonitorLocker* ml) {
   return false;
 }
 
-bool Handle::IssueWrite(std::unique_ptr<OverlappedBuffer> buffer) {
-  MonitorLocker ml(&monitor_);
+bool Handle::IssueWriteLocked(MonitorLocker* ml,
+                              std::unique_ptr<OverlappedBuffer> buffer) {
   ASSERT(type_ != kListenSocket);
   ASSERT(!HasPendingWrite());
   ASSERT(buffer->operation() == OverlappedBuffer::kWrite);
@@ -400,9 +404,10 @@
   return false;
 }
 
-bool Handle::IssueSendTo(std::unique_ptr<OverlappedBuffer> buffer,
-                         struct sockaddr* sa,
-                         socklen_t sa_len) {
+bool Handle::IssueSendToLocked(MonitorLocker* ml,
+                               std::unique_ptr<OverlappedBuffer> buffer,
+                               struct sockaddr* sa,
+                               socklen_t sa_len) {
   return false;
 }
 
@@ -434,11 +439,16 @@
   return IsClosing() && !HasPendingRead() && !HasPendingWrite();
 }
 
+void DirectoryWatchHandle::Start() {
+  MonitorLocker ml(&monitor_);
+  IssueReadLocked(&ml);
+}
+
 bool DirectoryWatchHandle::IsClosed() {
   return IsClosing() && !HasPendingRead();
 }
 
-bool DirectoryWatchHandle::IssueRead() {
+bool DirectoryWatchHandle::IssueReadLocked(MonitorLocker* ml) {
   // It may have been started before, as we start the directory-handler when
   // we create it.
   if (HasPendingRead() || (data_ready_ != nullptr)) {
@@ -470,7 +480,7 @@
     // Don't dispose of the buffer, as it will still complete (with length 0).
   }
 
-  DoClose();
+  DoCloseLocked(&ml);
 }
 
 void SocketHandle::HandleIssueError() {
@@ -483,9 +493,7 @@
   WSASetLastError(error);
 }
 
-bool ListenSocket::IssueAccept() {
-  MonitorLocker ml(&monitor_);
-
+bool ListenSocket::IssueAcceptLocked(MonitorLocker* ml) {
   auto buffer = OverlappedBuffer::AllocateAcceptBuffer(this);
   DWORD received;
   BOOL ok;
@@ -508,7 +516,7 @@
 
   // Always keep 5 outstanding accepts going, to enhance performance.
   for (intptr_t i = 0; i < kMinIssuedAccepts; i++) {
-    if (!IssueAccept()) {
+    if (!IssueAcceptLocked(&ml)) {
       return false;
     }
   }
@@ -581,7 +589,7 @@
   }
 }
 
-void ListenSocket::DoClose() {
+void ListenSocket::DoCloseLocked(MonitorLocker* ml) {
   closesocket(socket());
   handle_ = INVALID_HANDLE_VALUE;
 
@@ -617,7 +625,7 @@
   // We have less than 5 pending accepts and are not closing try to queue
   // another accept.
   if (!IsClosing() && (pending_accept_count_ < kMinIssuedAccepts)) {
-    IssueAccept();
+    IssueAcceptLocked(&ml);
   }
 
   return result;
@@ -649,7 +657,7 @@
   if (data_ready_->IsEmpty()) {
     data_ready_ = nullptr;
     if (!IsClosing() && !IsClosedRead()) {
-      IssueRead();
+      IssueReadLocked(&ml);
     }
   }
   return num_bytes;
@@ -677,7 +685,7 @@
   // entirety to match how recvfrom works in a socket.
   data_ready_ = nullptr;
   if (!IsClosing() && !IsClosedRead()) {
-    IssueRecvFrom();
+    IssueRecvFromLocked(&ml);
   }
   return num_bytes;
 }
@@ -694,7 +702,7 @@
   int truncated_bytes = Utils::Minimum<intptr_t>(num_bytes, INT_MAX);
   auto buffer = OverlappedBuffer::AllocateWriteBuffer(this, truncated_bytes);
   buffer->Write(data, truncated_bytes);
-  if (!IssueWrite(std::move(buffer))) {
+  if (!IssueWriteLocked(&ml, std::move(buffer))) {
     return -1;
   }
   return truncated_bytes;
@@ -719,7 +727,7 @@
   }
   auto buffer = OverlappedBuffer::AllocateSendToBuffer(this, num_bytes);
   buffer->Write(data, num_bytes);
-  if (!IssueSendTo(std::move(buffer), sa, sa_len)) {
+  if (!IssueSendToLocked(&ml, std::move(buffer), sa, sa_len)) {
     return -1;
   }
   return num_bytes;
@@ -826,23 +834,21 @@
   return 0;
 }
 
-void StdHandle::DoClose() {
-  {
-    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);
+void StdHandle::DoCloseLocked(MonitorLocker* ml) {
+  if (write_thread_exists_) {
+    write_thread_running_ = false;
+    ml->Notify();
+    while (write_thread_exists_) {
+      ml->Wait(Monitor::kNoTimeout);
     }
-    Handle::DoClose();
+    // Join the thread.
+    DWORD res = WaitForSingleObject(thread_handle_, INFINITE);
+    CloseHandle(thread_handle_);
+    ASSERT(res == WAIT_OBJECT_0);
   }
-  MutexLocker ml(stdin_mutex_);
+  Handle::DoCloseLocked(ml);
+
+  MutexLocker stdin_mutex_locker(stdin_mutex_);
   stdin_->Release();
   StdHandle::stdin_ = nullptr;
 }
@@ -865,14 +871,14 @@
   }
 }
 
-void ClientSocket::DoClose() {
+void ClientSocket::DoCloseLocked(MonitorLocker* ml) {
   // Always do a shutdown before initiating a disconnect.
   shutdown(socket(), SD_BOTH);
-  IssueDisconnect();
+  IssueDisconnectLocked(ml);
   handle_ = INVALID_HANDLE_VALUE;
 }
 
-bool ClientSocket::IssueRead() {
+bool ClientSocket::IssueReadLocked(MonitorLocker* ml) {
   ASSERT(!HasPendingRead());
 
   // TODO(sgjesse): Use a MTU value here. Only the loopback adapter can
@@ -893,7 +899,8 @@
   return false;
 }
 
-bool ClientSocket::IssueWrite(std::unique_ptr<OverlappedBuffer> buffer) {
+bool ClientSocket::IssueWriteLocked(MonitorLocker* ml,
+                                    std::unique_ptr<OverlappedBuffer> buffer) {
   ASSERT(!HasPendingWrite());
   ASSERT(buffer->operation() == OverlappedBuffer::kWrite);
 
@@ -909,7 +916,7 @@
   return false;
 }
 
-void ClientSocket::IssueDisconnect() {
+void ClientSocket::IssueDisconnectLocked(MonitorLocker* ml) {
   auto buffer = OverlappedBuffer::AllocateDisconnectBuffer(this);
   BOOL ok = EventHandler::delegate()->disconnect_ex()(
       socket(), buffer->GetCleanOverlapped(), TF_REUSE_SOCKET, 0);
@@ -950,7 +957,8 @@
   // If the port is set, we already listen for this socket in Dart.
   // Handle the cases here.
   if (!IsClosedRead() && ((Mask() & kInEventMask) != 0)) {
-    IssueRead();
+    MonitorLocker ml(&monitor_);
+    IssueReadLocked(&ml);
   }
   if (!IsClosedWrite()) {
     DispatchOutEventIfEnabled(this);
@@ -969,11 +977,10 @@
   return true;
 }
 
-bool DatagramSocket::IssueSendTo(std::unique_ptr<OverlappedBuffer> buffer,
-                                 struct sockaddr* sa,
-                                 socklen_t sa_len) {
-  MonitorLocker ml(&monitor_);
-
+bool DatagramSocket::IssueSendToLocked(MonitorLocker* ml,
+                                       std::unique_ptr<OverlappedBuffer> buffer,
+                                       struct sockaddr* sa,
+                                       socklen_t sa_len) {
   ASSERT(!HasPendingWrite());
   ASSERT(buffer->operation() == OverlappedBuffer::kSendTo);
 
@@ -989,8 +996,7 @@
   return false;
 }
 
-bool DatagramSocket::IssueRecvFrom() {
-  MonitorLocker ml(&monitor_);
+bool DatagramSocket::IssueRecvFromLocked(MonitorLocker* ml) {
   ASSERT(!HasPendingRead());
 
   auto buffer =
@@ -1014,7 +1020,7 @@
   return IsClosing() && !HasPendingRead() && !HasPendingWrite();
 }
 
-void DatagramSocket::DoClose() {
+void DatagramSocket::DoCloseLocked(MonitorLocker* ml) {
   // Just close the socket. This will cause any queued requests to be aborted.
   closesocket(socket());
   MarkClosedRead();
@@ -1041,106 +1047,107 @@
     handle->Retain();
     RefCntReleaseScope<Handle> rh(handle);
 
-    if (handle->is_listen_socket()) {
-      ListenSocket* listen_socket = reinterpret_cast<ListenSocket*>(handle);
-
-      MonitorLocker ml(&listen_socket->monitor_);
-
-      if (IS_COMMAND(msg->data, kReturnTokenCommand)) {
-        listen_socket->ReturnTokens(msg->dart_port, TOKEN_COUNT(msg->data));
-      } else if (IS_COMMAND(msg->data, kSetEventMaskCommand)) {
-        // `events` can only have kInEvent/kOutEvent flags set.
-        intptr_t events = msg->data & EVENT_MASK;
-        ASSERT(0 == (events & ~(kInEventMask | kOutEventMask)));
-        listen_socket->SetPortAndMask(msg->dart_port, events);
-        listen_socket->DispatchCompletedAcceptsLocked(&ml);
-      } else if (IS_COMMAND(msg->data, kCloseCommand)) {
-        if (msg->dart_port != ILLEGAL_PORT) {
-          listen_socket->RemovePort(msg->dart_port);
-        }
-
-        // We only close the socket file descriptor from the operating
-        // system if there are no other dart socket objects which
-        // are listening on the same (address, port) combination.
-        ListeningSocketRegistry* registry = ListeningSocketRegistry::Instance();
-        MutexLocker locker(registry->mutex());
-        if (registry->CloseSafe(socket)) {
-          ASSERT(listen_socket->Mask() == 0);
-          listen_socket->Close();
-          socket->CloseFd();
-        }
-        socket->SetClosedFd();
-        DartUtils::PostInt32(msg->dart_port, 1 << kDestroyedEvent);
-      } else {
-        UNREACHABLE();
-      }
-    } else {
-      MonitorLocker ml(&handle->monitor_);
-
-      if (IS_COMMAND(msg->data, kReturnTokenCommand)) {
+    MonitorLocker hl(&handle->monitor_);
+    switch (msg->data & COMMAND_MASK) {
+      case 1 << kReturnTokenCommand:
         handle->ReturnTokens(msg->dart_port, TOKEN_COUNT(msg->data));
-      } else if (IS_COMMAND(msg->data, kSetEventMaskCommand)) {
+        break;
+
+      case 1 << kSetEventMaskCommand: {
         // `events` can only have kInEvent/kOutEvent flags set.
         intptr_t events = msg->data & EVENT_MASK;
         ASSERT(0 == (events & ~(kInEventMask | kOutEventMask)));
 
         handle->SetPortAndMask(msg->dart_port, events);
-
-        // Issue a read.
-        if ((handle->Mask() & kInEventMask) != 0) {
-          if (handle->is_datagram_socket()) {
-            handle->IssueRecvFrom();
-          } else if (handle->is_client_socket()) {
-            if (reinterpret_cast<ClientSocket*>(handle)->is_connected()) {
-              handle->IssueRead();
+        if (handle->is_listen_socket()) {
+          static_cast<ListenSocket*>(handle)->DispatchCompletedAcceptsLocked(
+              &hl);
+        } else {
+          // Issue a read.
+          if ((handle->Mask() & kInEventMask) != 0) {
+            if (handle->is_datagram_socket()) {
+              handle->IssueRecvFromLocked(&hl);
+            } else if (!handle->is_client_socket() ||
+                       reinterpret_cast<ClientSocket*>(handle)
+                           ->is_connected()) {
+              handle->IssueReadLocked(&hl);
             }
-          } else {
-            handle->IssueRead();
           }
-        }
 
-        // If out events (can write events) have been requested, and there
-        // are no pending writes, meaning any writes are already complete,
-        // post an out event immediately.
-        if ((events & kOutEventMask) != 0) {
-          if (!handle->HasPendingWrite()) {
-            if (handle->is_client_socket()) {
-              if (reinterpret_cast<ClientSocket*>(handle)->is_connected()) {
-                DispatchOutEventIfEnabled(handle);
-              }
-            } else {
+          // If out events (can write events) have been requested, and there
+          // are no pending writes, meaning any writes are already complete,
+          // post an out event immediately.
+          //
+          // Client sockets are only notified if they are connected.
+          if ((events & kOutEventMask) != 0 && !handle->HasPendingWrite()) {
+            if (!handle->is_client_socket() ||
+                reinterpret_cast<ClientSocket*>(handle)->is_connected()) {
               DispatchOutEventIfEnabled(handle);
             }
           }
-        }
-        // Similarly, if in events (can read events) have been requested, and
-        // there is pending data available, post an in event immediately.
-        if ((events & kInEventMask) != 0) {
-          if (handle->data_ready_ != nullptr &&
-              !handle->data_ready_->IsEmpty()) {
-            DispatchInEventIfEnabled(handle);
+
+          // Similarly, if in events (can read events) have been requested, and
+          // there is pending data available, post an in event immediately.
+          if ((events & kInEventMask) != 0) {
+            if (handle->data_ready_ != nullptr &&
+                !handle->data_ready_->IsEmpty()) {
+              DispatchInEventIfEnabled(handle);
+            }
           }
         }
-      } else if (IS_COMMAND(msg->data, kShutdownReadCommand)) {
-        ASSERT(handle->is_client_socket());
+        break;
+      }
 
+      case 1 << kShutdownReadCommand: {
+        ASSERT(handle->is_client_socket());
         ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(handle);
         client_socket->Shutdown(SD_RECEIVE);
-      } else if (IS_COMMAND(msg->data, kShutdownWriteCommand)) {
-        ASSERT(handle->is_client_socket());
+        break;
+      }
 
+      case 1 << kShutdownWriteCommand: {
+        ASSERT(handle->is_client_socket());
         ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(handle);
         client_socket->Shutdown(SD_SEND);
-      } else if (IS_COMMAND(msg->data, kCloseCommand)) {
+        break;
+      }
+
+      case 1 << kCloseCommand: {
         if (IS_SIGNAL_SOCKET(msg->data)) {
           Process::ClearSignalHandlerByFd(socket->fd(), socket->isolate_port());
         }
-        handle->SetPortAndMask(msg->dart_port, 0);
-        handle->Close();
-        socket->CloseFd();
-      } else {
-        UNREACHABLE();
+        bool can_close_handle = true;
+        if (handle->is_listen_socket()) {
+          // We only close the socket file descriptor if there are no other
+          // dart socket objects which are listening on the same
+          // (address, port) combination.
+          ListeningSocketRegistry* registry =
+              ListeningSocketRegistry::Instance();
+          MutexLocker locker(registry->mutex());
+          if (!registry->CloseSafe(socket)) {
+            // Other sockets are listening to the same OS socket. Do not close
+            // OS socket, but deassociate it from the message port and tell
+            // Dart side that this socket was destroyed.
+            can_close_handle = false;
+            handle->RemovePort(msg->dart_port);
+            DartUtils::PostInt32(msg->dart_port, 1 << kDestroyedEvent);
+            socket->SetClosedFd();
+          }
+        }
+
+        if (can_close_handle) {
+          // Set response port so that kDestroyedEvent notification is
+          // delivered to the listener.
+          handle->SetPortAndMask(msg->dart_port, 0);
+          handle->CloseLocked(&hl);
+          socket->CloseFd();
+        }
+        break;
       }
+
+      default:
+        UNREACHABLE();
+        break;
     }
 
     NotifyDestroyedIfClosed(handle);
diff --git a/runtime/bin/eventhandler_win.h b/runtime/bin/eventhandler_win.h
index 6b125fc..e5eeff2 100644
--- a/runtime/bin/eventhandler_win.h
+++ b/runtime/bin/eventhandler_win.h
@@ -185,8 +185,8 @@
                           socklen_t sa_len);
 
   // Internal interface used by the event handler.
-  virtual bool IssueRead();
-  virtual bool IssueRecvFrom();
+  virtual bool IssueReadLocked(MonitorLocker* ml);
+  virtual bool IssueRecvFromLocked(MonitorLocker* ml);
   bool HasPendingRead();
   bool HasPendingWrite();
   void ReadComplete(std::unique_ptr<OverlappedBuffer> buffer);
@@ -204,7 +204,9 @@
   HANDLE handle() { return handle_; }
 
   void Close();
-  virtual void DoClose();
+  void CloseLocked(MonitorLocker* ml);
+
+  virtual void DoCloseLocked(MonitorLocker* ml);
   virtual bool IsClosed() = 0;
 
   bool IsHandleClosed() const { return handle_ == INVALID_HANDLE_VALUE; }
@@ -269,10 +271,12 @@
   void WaitForReadThreadFinished();
   void NotifyReadThreadFinished();
 
-  virtual bool IssueWrite(std::unique_ptr<OverlappedBuffer> buffer);
-  virtual bool IssueSendTo(std::unique_ptr<OverlappedBuffer> buffer,
-                           struct sockaddr* sa,
-                           socklen_t sa_len);
+  virtual bool IssueWriteLocked(MonitorLocker* ml,
+                                std::unique_ptr<OverlappedBuffer> buffer);
+  virtual bool IssueSendToLocked(MonitorLocker* ml,
+                                 std::unique_ptr<OverlappedBuffer> buffer,
+                                 struct sockaddr* sa,
+                                 socklen_t sa_len);
 
   int flags_;
 
@@ -305,7 +309,7 @@
  public:
   static StdHandle* Stdin(HANDLE handle);
 
-  virtual void DoClose();
+  virtual void DoCloseLocked(MonitorLocker* ml);
   virtual intptr_t Write(const void* buffer, intptr_t num_bytes);
 
   void WriteSyncCompleteAsync();
@@ -347,8 +351,9 @@
 
   virtual bool IsClosed();
 
-  virtual bool IssueRead();
+  virtual bool IssueReadLocked(MonitorLocker* ml);
 
+  void Start();
   void Stop();
 
  private:
@@ -397,7 +402,7 @@
   bool HasPendingAccept() { return pending_accept_count_ > 0; }
   void AcceptComplete(std::unique_ptr<OverlappedBuffer> buffer);
 
-  virtual void DoClose();
+  virtual void DoCloseLocked(MonitorLocker* ml);
   virtual bool IsClosed();
 
   int pending_accept_count() { return pending_accept_count_; }
@@ -409,7 +414,7 @@
  private:
   static constexpr intptr_t kMinIssuedAccepts = 5;
 
-  bool IssueAccept();
+  bool IssueAcceptLocked(MonitorLocker* ml);
 
   // The number of asynchronous `IssueAccept` operations which haven't completed
   // yet.
@@ -449,12 +454,12 @@
   void Shutdown(int how);
 
   // Internal interface used by the event handler.
-  virtual bool IssueRead();
-  void IssueDisconnect();
+  virtual bool IssueReadLocked(MonitorLocker* ml);
+  void IssueDisconnectLocked(MonitorLocker* ml);
   void DisconnectComplete();
   void ConnectComplete();
 
-  virtual void DoClose();
+  virtual void DoCloseLocked(MonitorLocker* ml);
   virtual bool IsClosed();
 
   // If `ClientSocket` was constructed with a `remote_addr`, populate `addr`
@@ -475,7 +480,8 @@
 #endif
 
  private:
-  virtual bool IssueWrite(std::unique_ptr<OverlappedBuffer> buffer);
+  virtual bool IssueWriteLocked(MonitorLocker* ml,
+                                std::unique_ptr<OverlappedBuffer> buffer);
 
   ClientSocket* next_;
   bool connected_;
@@ -501,15 +507,16 @@
   }
 
   // Internal interface used by the event handler.
-  virtual bool IssueRecvFrom();
+  virtual bool IssueRecvFromLocked(MonitorLocker* ml);
 
-  virtual void DoClose();
+  virtual void DoCloseLocked(MonitorLocker* ml);
   virtual bool IsClosed();
 
  private:
-  virtual bool IssueSendTo(std::unique_ptr<OverlappedBuffer> buffer,
-                           sockaddr* sa,
-                           socklen_t sa_len);
+  virtual bool IssueSendToLocked(MonitorLocker* ml,
+                                 std::unique_ptr<OverlappedBuffer> buffer,
+                                 sockaddr* sa,
+                                 socklen_t sa_len);
 
   DISALLOW_COPY_AND_ASSIGN(DatagramSocket);
 };
diff --git a/runtime/bin/file_system_watcher_win.cc b/runtime/bin/file_system_watcher_win.cc
index 56925b2..ebb2861 100644
--- a/runtime/bin/file_system_watcher_win.cc
+++ b/runtime/bin/file_system_watcher_win.cc
@@ -57,9 +57,7 @@
 
   DirectoryWatchHandle* handle =
       new DirectoryWatchHandle(dir, list_events, recursive);
-  // Issue a read directly, to be sure events are tracked from now on. This is
-  // okay, since in Dart, we create the socket and start reading immediately.
-  handle->IssueRead();
+  handle->Start();
   return reinterpret_cast<intptr_t>(handle);
 }
 
diff --git a/runtime/bin/thread_win.cc b/runtime/bin/thread_win.cc
index fea1a63..6f7b9c0 100644
--- a/runtime/bin/thread_win.cc
+++ b/runtime/bin/thread_win.cc
@@ -107,30 +107,30 @@
 }
 
 Monitor::Monitor() {
-  InitializeCriticalSection(&data_.cs_);
+  InitializeSRWLock(&data_.lock_);
   InitializeConditionVariable(&data_.cond_);
 }
 
-Monitor::~Monitor() {
-  DeleteCriticalSection(&data_.cs_);
-}
+Monitor::~Monitor() {}
 
 void Monitor::Enter() {
-  EnterCriticalSection(&data_.cs_);
+  AcquireSRWLockExclusive(&data_.lock_);
 }
 
 void Monitor::Exit() {
-  LeaveCriticalSection(&data_.cs_);
+  ReleaseSRWLockExclusive(&data_.lock_);
 }
 
 Monitor::WaitResult Monitor::Wait(int64_t millis) {
   Monitor::WaitResult retval = kNotified;
   if (millis == kNoTimeout) {
-    SleepConditionVariableCS(&data_.cond_, &data_.cs_, INFINITE);
+    SleepConditionVariableSRW(&data_.cond_, &data_.lock_, INFINITE,
+                              /*Flags=*/0);
   } else {
     // Wait for the given period of time for a Notify or a NotifyAll
     // event.
-    if (!SleepConditionVariableCS(&data_.cond_, &data_.cs_, millis)) {
+    if (!SleepConditionVariableSRW(&data_.cond_, &data_.lock_, millis,
+                                   /*Flags=*/0)) {
       ASSERT(GetLastError() == ERROR_TIMEOUT);
       retval = kTimedOut;
     }
diff --git a/runtime/bin/thread_win.h b/runtime/bin/thread_win.h
index 99691d2..42de4b2 100644
--- a/runtime/bin/thread_win.h
+++ b/runtime/bin/thread_win.h
@@ -35,7 +35,7 @@
   MonitorData() {}
   ~MonitorData() {}
 
-  CRITICAL_SECTION cs_;
+  SRWLOCK lock_;
   CONDITION_VARIABLE cond_;
 
   friend class Monitor;