[vm/concurrent] Use ffi native resolver for dart:concurrent native functions.

Ffi native interface should be faster, more effecient for Dart->C++ communication, so switching to it.
TEST=ci

Change-Id: I9e1d18a666737799194c0435c300e4b81783c0ec
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/377541
Commit-Queue: Alexander Aprelev <aam@google.com>
Reviewed-by: Daco Harkes <dacoharkes@google.com>
diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn
index 4475779..addf9a3 100644
--- a/runtime/bin/BUILD.gn
+++ b/runtime/bin/BUILD.gn
@@ -14,7 +14,6 @@
 import("builtin_impl_sources.gni")
 import("builtin_sources.gni")
 import("cli_sources.gni")
-import("concurrent_impl_sources.gni")
 import("io_impl_sources.gni")
 import("io_sources.gni")
 import("native_assets_impl_sources.gni")
@@ -136,37 +135,11 @@
   ]
 }
 
-template("build_concurrent_api") {
-  extra_configs = []
-  if (defined(invoker.extra_configs)) {
-    extra_configs += invoker.extra_configs
-  }
-  source_set(target_name) {
-    configs += [ "..:dart_config" ] + extra_configs
-    deps = []
-    include_dirs = [ ".." ]
-    sources = concurrent_api_sources
-    sources += [
-      "concurrent_natives.cc",
-      "concurrent_natives.h",
-    ]
-  }
+# TODO(aam): Remove once https://dart-review.googlesource.com/c/sdk/+/377541
+# rolls into flutter engine.
+source_set("concurrent_api") {
 }
-
-build_concurrent_api("concurrent_api") {
-  extra_configs = [
-    "..:dart_maybe_product_config",
-    "..:dart_os_config",
-    "..:dart_arch_config",
-  ]
-}
-
-build_concurrent_api("concurrent_api_product") {
-  extra_configs = [
-    "..:dart_product_config",
-    "..:dart_os_config",
-    "..:dart_arch_config",
-  ]
+source_set("concurrent_api_product") {
 }
 
 static_library("crashpad") {
@@ -881,12 +854,6 @@
       deps += [ ":standalone_dart_io" ]
     }
 
-    if (use_product_mode) {
-      deps += [ ":concurrent_api_product" ]
-    } else {
-      deps += [ ":concurrent_api" ]
-    }
-
     configs += [ ":export_api_symbols" ]
 
     ldflags = extra_ldflags
@@ -1133,7 +1100,6 @@
   }
 
   deps = [
-    ":concurrent_api",
     ":crashpad",
     ":dart_kernel_platform_cc",
     ":dart_snapshot_cc",
diff --git a/runtime/bin/builtin_natives.cc b/runtime/bin/builtin_natives.cc
index 5485481..bd28a12 100644
--- a/runtime/bin/builtin_natives.cc
+++ b/runtime/bin/builtin_natives.cc
@@ -13,7 +13,6 @@
 #include "platform/assert.h"
 
 #include "bin/builtin.h"
-#include "bin/concurrent_natives.h"
 #include "bin/dartutils.h"
 #include "bin/file.h"
 #include "bin/io_natives.h"
@@ -25,8 +24,7 @@
 // Lists the native functions implementing basic functionality in
 // standalone dart, such as printing, file I/O, and platform information.
 // Advanced I/O classes like sockets and process management are implemented
-// using functions listed in io_natives.cc and synchronization primitives -
-// in concurrent_natives.cc.
+// using functions listed in io_natives.cc.
 #define BUILTIN_NATIVE_LIST(V) V(Builtin_PrintString, 1)
 
 BUILTIN_NATIVE_LIST(DECLARE_FUNCTION);
@@ -65,10 +63,6 @@
   }
   Dart_NativeFunction result =
       IONativeLookup(name, argument_count, auto_setup_scope);
-  if (result != nullptr) {
-    return result;
-  }
-  result = ConcurrentNativeLookup(name, argument_count, auto_setup_scope);
   if (result == nullptr) {
     result = Builtin_DummyNative;
   }
diff --git a/runtime/bin/concurrent.cc b/runtime/bin/concurrent.cc
deleted file mode 100644
index 61a8391..0000000
--- a/runtime/bin/concurrent.cc
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright (c) 2024, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "bin/builtin.h"
-#include "bin/thread.h"
-#include "include/dart_api.h"
-
-namespace dart {
-namespace bin {
-
-static constexpr int kMutexNativeField = 0;
-static constexpr int kCondVarNativeField = 0;
-
-static void DeleteMutex(void* isolate_data, void* mutex_pointer) {
-  delete reinterpret_cast<Mutex*>(mutex_pointer);
-}
-
-void FUNCTION_NAME(Mutex_Initialize)(Dart_NativeArguments args) {
-  Dart_Handle mutex_obj = Dart_GetNativeArgument(args, 0);
-  Mutex* mutex = new Mutex();
-  Dart_Handle err = Dart_SetNativeInstanceField(
-      mutex_obj, kMutexNativeField, reinterpret_cast<intptr_t>(mutex));
-  if (Dart_IsError(err)) {
-    delete mutex;
-    Dart_PropagateError(err);
-  }
-  Dart_NewFinalizableHandle(mutex_obj, mutex, sizeof(Mutex), DeleteMutex);
-}
-
-void FUNCTION_NAME(Mutex_Lock)(Dart_NativeArguments args) {
-  Dart_Handle mutex_obj = Dart_GetNativeArgument(args, 0);
-  Mutex* mutex;
-  Dart_Handle result = Dart_GetNativeInstanceField(
-      mutex_obj, kMutexNativeField, reinterpret_cast<intptr_t*>(&mutex));
-  if (Dart_IsError(result)) {
-    Dart_PropagateError(result);
-  }
-  mutex->Lock();
-  Dart_SetReturnValue(args, Dart_Null());
-}
-
-void FUNCTION_NAME(Mutex_Unlock)(Dart_NativeArguments args) {
-  Dart_Handle mutex_obj = Dart_GetNativeArgument(args, 0);
-  Mutex* mutex;
-  Dart_Handle result = Dart_GetNativeInstanceField(
-      mutex_obj, kMutexNativeField, reinterpret_cast<intptr_t*>(&mutex));
-  if (Dart_IsError(result)) {
-    Dart_PropagateError(result);
-  }
-  mutex->Unlock();
-  Dart_SetReturnValue(args, Dart_Null());
-}
-
-static void DeleteConditionVariable(void* isolate_data, void* condvar_pointer) {
-  delete reinterpret_cast<ConditionVariable*>(condvar_pointer);
-}
-
-void FUNCTION_NAME(ConditionVariable_Initialize)(Dart_NativeArguments args) {
-  Dart_Handle condvar_obj = Dart_GetNativeArgument(args, 0);
-  ConditionVariable* condvar = new ConditionVariable();
-  Dart_Handle err = Dart_SetNativeInstanceField(
-      condvar_obj, kCondVarNativeField, reinterpret_cast<intptr_t>(condvar));
-  if (Dart_IsError(err)) {
-    delete condvar;
-    Dart_PropagateError(err);
-  }
-  Dart_NewFinalizableHandle(condvar_obj, condvar, sizeof(ConditionVariable),
-                            DeleteConditionVariable);
-}
-
-void FUNCTION_NAME(ConditionVariable_Wait)(Dart_NativeArguments args) {
-  Dart_Handle condvar_obj = Dart_GetNativeArgument(args, 0);
-  Dart_Handle mutex_obj = Dart_GetNativeArgument(args, 1);
-  Mutex* mutex;
-  Dart_Handle result_mutex = Dart_GetNativeInstanceField(
-      mutex_obj, kCondVarNativeField, reinterpret_cast<intptr_t*>(&mutex));
-  if (Dart_IsError(result_mutex)) {
-    Dart_PropagateError(result_mutex);
-  }
-  ConditionVariable* condvar;
-  Dart_Handle result_condvar = Dart_GetNativeInstanceField(
-      condvar_obj, kCondVarNativeField, reinterpret_cast<intptr_t*>(&condvar));
-  if (Dart_IsError(result_condvar)) {
-    Dart_PropagateError(result_condvar);
-  }
-  condvar->Wait(mutex);
-  Dart_SetReturnValue(args, Dart_Null());
-}
-
-void FUNCTION_NAME(ConditionVariable_Notify)(Dart_NativeArguments args) {
-  Dart_Handle condvar_obj = Dart_GetNativeArgument(args, 0);
-  ConditionVariable* condvar;
-  Dart_Handle result_condvar = Dart_GetNativeInstanceField(
-      condvar_obj, kCondVarNativeField, reinterpret_cast<intptr_t*>(&condvar));
-  if (Dart_IsError(result_condvar)) {
-    Dart_PropagateError(result_condvar);
-  }
-  condvar->Notify();
-  Dart_SetReturnValue(args, Dart_Null());
-}
-
-}  // namespace bin
-}  // namespace dart
diff --git a/runtime/bin/concurrent_natives.cc b/runtime/bin/concurrent_natives.cc
deleted file mode 100644
index c660921..0000000
--- a/runtime/bin/concurrent_natives.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) 2024, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "bin/concurrent_natives.h"
-
-#include "bin/builtin.h"
-
-namespace dart {
-namespace bin {
-
-// Lists the native functions implementing advanced dart:io classes.
-// Some classes, like File and Directory, list their implementations in
-// builtin_natives.cc instead.
-#define CONCURRENT_NATIVE_LIST(V)                                              \
-  V(Mutex_Initialize, 1)                                                       \
-  V(Mutex_Lock, 1)                                                             \
-  V(Mutex_Unlock, 1)                                                           \
-  V(ConditionVariable_Initialize, 1)                                           \
-  V(ConditionVariable_Wait, 2)                                                 \
-  V(ConditionVariable_Notify, 1)
-
-CONCURRENT_NATIVE_LIST(DECLARE_FUNCTION);
-
-static const struct NativeEntries {
-  const char* name_;
-  Dart_NativeFunction function_;
-  int argument_count_;
-} ConcurrentEntries[] = {CONCURRENT_NATIVE_LIST(REGISTER_FUNCTION)};
-
-Dart_NativeFunction ConcurrentNativeLookup(Dart_Handle name,
-                                           int argument_count,
-                                           bool* auto_setup_scope) {
-  const char* function_name = nullptr;
-  Dart_Handle result = Dart_StringToCString(name, &function_name);
-  ASSERT(!Dart_IsError(result));
-  ASSERT(function_name != nullptr);
-  ASSERT(auto_setup_scope != nullptr);
-  *auto_setup_scope = true;
-  int num_entries = sizeof(ConcurrentEntries) / sizeof(struct NativeEntries);
-  for (int i = 0; i < num_entries; i++) {
-    const struct NativeEntries* entry = &(ConcurrentEntries[i]);
-    if ((strcmp(function_name, entry->name_) == 0) &&
-        (entry->argument_count_ == argument_count)) {
-      return reinterpret_cast<Dart_NativeFunction>(entry->function_);
-    }
-  }
-  return nullptr;
-}
-
-const uint8_t* ConcurrentNativeSymbol(Dart_NativeFunction nf) {
-  int num_entries = sizeof(ConcurrentEntries) / sizeof(struct NativeEntries);
-  for (int i = 0; i < num_entries; i++) {
-    const struct NativeEntries* entry = &(ConcurrentEntries[i]);
-    if (reinterpret_cast<Dart_NativeFunction>(entry->function_) == nf) {
-      return reinterpret_cast<const uint8_t*>(entry->name_);
-    }
-  }
-  return nullptr;
-}
-
-}  // namespace bin
-}  // namespace dart
diff --git a/runtime/bin/concurrent_natives.h b/runtime/bin/concurrent_natives.h
deleted file mode 100644
index 4de04b4..0000000
--- a/runtime/bin/concurrent_natives.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2024, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef RUNTIME_BIN_CONCURRENT_NATIVES_H_
-#define RUNTIME_BIN_CONCURRENT_NATIVES_H_
-
-#include "include/dart_api.h"
-
-namespace dart {
-namespace bin {
-
-Dart_NativeFunction ConcurrentNativeLookup(Dart_Handle name,
-                                           int argument_count,
-                                           bool* auto_setup_scope);
-
-const uint8_t* ConcurrentNativeSymbol(Dart_NativeFunction nf);
-
-}  // namespace bin
-}  // namespace dart
-
-#endif  // RUNTIME_BIN_CONCURRENT_NATIVES_H_
diff --git a/runtime/bin/thread.h b/runtime/bin/thread.h
index 313de35..e41e8b6 100644
--- a/runtime/bin/thread.h
+++ b/runtime/bin/thread.h
@@ -69,25 +69,9 @@
  private:
   MutexData data_;
 
-  friend class ConditionVariable;
-
   DISALLOW_COPY_AND_ASSIGN(Mutex);
 };
 
-class ConditionVariable {
- public:
-  ConditionVariable();
-  ~ConditionVariable();
-
-  void Wait(Mutex* mutex);
-  void Notify();
-
- private:
-  ConditionVariableData data_;
-
-  DISALLOW_COPY_AND_ASSIGN(ConditionVariable);
-};
-
 class Monitor {
  public:
   enum WaitResult { kNotified, kTimedOut };
diff --git a/runtime/bin/thread_absl.cc b/runtime/bin/thread_absl.cc
index 245d37a..23bc5e55 100644
--- a/runtime/bin/thread_absl.cc
+++ b/runtime/bin/thread_absl.cc
@@ -150,19 +150,6 @@
   data_.mutex()->Unlock();
 }
 
-ConditionVariable::ConditionVariable() {}
-
-ConditionVariable::~ConditionVariable() {}
-
-ABSL_NO_THREAD_SAFETY_ANALYSIS
-void ConditionVariable::Wait(Mutex* mutex) {
-  data_.cond()->Wait(mutex->data_.mutex());
-}
-
-void ConditionVariable::Notify() {
-  data_.cond()->Signal();
-}
-
 Monitor::Monitor() : data_() {}
 
 Monitor::~Monitor() {}
diff --git a/runtime/bin/thread_absl.h b/runtime/bin/thread_absl.h
index 3e8add4..190af2e 100644
--- a/runtime/bin/thread_absl.h
+++ b/runtime/bin/thread_absl.h
@@ -30,27 +30,11 @@
   absl::Mutex mutex_;
 
   friend class Mutex;
-  friend class ConditionVariable;
 
   DISALLOW_ALLOCATION();
   DISALLOW_COPY_AND_ASSIGN(MutexData);
 };
 
-class ConditionVariableData {
- private:
-  ConditionVariableData() : cond_() {}
-  ~ConditionVariableData() {}
-
-  absl::CondVar* cond() { return &cond_; }
-
-  absl::CondVar cond_;
-
-  friend class ConditionVariable;
-
-  DISALLOW_ALLOCATION();
-  DISALLOW_COPY_AND_ASSIGN(ConditionVariableData);
-};
-
 class MonitorData {
  private:
   MonitorData() : mutex_(), cond_() {}
diff --git a/runtime/bin/thread_fuchsia.cc b/runtime/bin/thread_fuchsia.cc
index 5a5d769..20d918b 100644
--- a/runtime/bin/thread_fuchsia.cc
+++ b/runtime/bin/thread_fuchsia.cc
@@ -193,37 +193,6 @@
   ASSERT(result == 0);  // Verify no other errors.
 }
 
-ConditionVariable::ConditionVariable() {
-  pthread_condattr_t cond_attr;
-  int result = pthread_condattr_init(&cond_attr);
-  VALIDATE_PTHREAD_RESULT(result);
-
-  result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
-  VALIDATE_PTHREAD_RESULT(result);
-
-  result = pthread_cond_init(data_.cond(), &cond_attr);
-  VALIDATE_PTHREAD_RESULT(result);
-
-  result = pthread_condattr_destroy(&cond_attr);
-  VALIDATE_PTHREAD_RESULT(result);
-}
-
-ConditionVariable::~ConditionVariable() {
-  int result = pthread_cond_destroy(data_.cond());
-  VALIDATE_PTHREAD_RESULT(result);
-}
-
-void ConditionVariable::Wait(Mutex* mutex) {
-  int result = pthread_cond_wait(data_.cond(), mutex->data_.mutex());
-  VALIDATE_PTHREAD_RESULT(result);
-}
-
-void ConditionVariable::Notify() {
-  // TODO(iposva): Do we need to track lock owners?
-  int result = pthread_cond_signal(data_.cond());
-  VALIDATE_PTHREAD_RESULT(result);
-}
-
 Monitor::Monitor() {
   pthread_mutexattr_t mutex_attr;
   int result = pthread_mutexattr_init(&mutex_attr);
diff --git a/runtime/bin/thread_fuchsia.h b/runtime/bin/thread_fuchsia.h
index c313065..95f2694 100644
--- a/runtime/bin/thread_fuchsia.h
+++ b/runtime/bin/thread_fuchsia.h
@@ -29,26 +29,11 @@
   pthread_mutex_t mutex_;
 
   friend class Mutex;
-  friend class ConditionVariable;
 
   DISALLOW_ALLOCATION();
   DISALLOW_COPY_AND_ASSIGN(MutexData);
 };
 
-class ConditionVariableData {
- private:
-  ConditionVariableData() {}
-  ~ConditionVariableData() {}
-
-  pthread_cond_t* cond() { return &cond_; }
-  pthread_cond_t cond_;
-
-  friend class ConditionVariable;
-
-  DISALLOW_ALLOCATION();
-  DISALLOW_COPY_AND_ASSIGN(ConditionVariableData);
-};
-
 class MonitorData {
  private:
   MonitorData() {}
diff --git a/runtime/bin/thread_linux.cc b/runtime/bin/thread_linux.cc
index c045aef..409131b 100644
--- a/runtime/bin/thread_linux.cc
+++ b/runtime/bin/thread_linux.cc
@@ -190,37 +190,6 @@
   ASSERT(result == 0);  // Verify no other errors.
 }
 
-ConditionVariable::ConditionVariable() {
-  pthread_condattr_t cond_attr;
-  int result = pthread_condattr_init(&cond_attr);
-  VALIDATE_PTHREAD_RESULT(result);
-
-  result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
-  VALIDATE_PTHREAD_RESULT(result);
-
-  result = pthread_cond_init(data_.cond(), &cond_attr);
-  VALIDATE_PTHREAD_RESULT(result);
-
-  result = pthread_condattr_destroy(&cond_attr);
-  VALIDATE_PTHREAD_RESULT(result);
-}
-
-ConditionVariable::~ConditionVariable() {
-  int result = pthread_cond_destroy(data_.cond());
-  VALIDATE_PTHREAD_RESULT(result);
-}
-
-void ConditionVariable::Wait(Mutex* mutex) {
-  int result = pthread_cond_wait(data_.cond(), mutex->data_.mutex());
-  VALIDATE_PTHREAD_RESULT(result);
-}
-
-void ConditionVariable::Notify() {
-  // TODO(iposva): Do we need to track lock owners?
-  int result = pthread_cond_signal(data_.cond());
-  VALIDATE_PTHREAD_RESULT(result);
-}
-
 Monitor::Monitor() {
   pthread_mutexattr_t mutex_attr;
   int result = pthread_mutexattr_init(&mutex_attr);
diff --git a/runtime/bin/thread_linux.h b/runtime/bin/thread_linux.h
index c55f9b2..b3f99c7 100644
--- a/runtime/bin/thread_linux.h
+++ b/runtime/bin/thread_linux.h
@@ -29,26 +29,11 @@
   pthread_mutex_t mutex_;
 
   friend class Mutex;
-  friend class ConditionVariable;
 
   DISALLOW_ALLOCATION();
   DISALLOW_COPY_AND_ASSIGN(MutexData);
 };
 
-class ConditionVariableData {
- private:
-  ConditionVariableData() {}
-  ~ConditionVariableData() {}
-
-  pthread_cond_t* cond() { return &cond_; }
-  pthread_cond_t cond_;
-
-  friend class ConditionVariable;
-
-  DISALLOW_ALLOCATION();
-  DISALLOW_COPY_AND_ASSIGN(ConditionVariableData);
-};
-
 class MonitorData {
  private:
   MonitorData() {}
diff --git a/runtime/bin/thread_macos.cc b/runtime/bin/thread_macos.cc
index 13c1413..6071333 100644
--- a/runtime/bin/thread_macos.cc
+++ b/runtime/bin/thread_macos.cc
@@ -184,27 +184,6 @@
   ASSERT(result == 0);  // Verify no other errors.
 }
 
-ConditionVariable::ConditionVariable() {
-  int result = pthread_cond_init(data_.cond(), nullptr);
-  VALIDATE_PTHREAD_RESULT(result);
-}
-
-ConditionVariable::~ConditionVariable() {
-  int result = pthread_cond_destroy(data_.cond());
-  VALIDATE_PTHREAD_RESULT(result);
-}
-
-void ConditionVariable::Wait(Mutex* mutex) {
-  int result = pthread_cond_wait(data_.cond(), mutex->data_.mutex());
-  VALIDATE_PTHREAD_RESULT(result);
-}
-
-void ConditionVariable::Notify() {
-  // TODO(iposva): Do we need to track lock owners?
-  int result = pthread_cond_signal(data_.cond());
-  VALIDATE_PTHREAD_RESULT(result);
-}
-
 Monitor::Monitor() {
   pthread_mutexattr_t attr;
   int result = pthread_mutexattr_init(&attr);
diff --git a/runtime/bin/thread_macos.h b/runtime/bin/thread_macos.h
index 494aa65..c45091e 100644
--- a/runtime/bin/thread_macos.h
+++ b/runtime/bin/thread_macos.h
@@ -29,26 +29,11 @@
   pthread_mutex_t mutex_;
 
   friend class Mutex;
-  friend class ConditionVariable;
 
   DISALLOW_ALLOCATION();
   DISALLOW_COPY_AND_ASSIGN(MutexData);
 };
 
-class ConditionVariableData {
- private:
-  ConditionVariableData() {}
-  ~ConditionVariableData() {}
-
-  pthread_cond_t* cond() { return &cond_; }
-  pthread_cond_t cond_;
-
-  friend class ConditionVariable;
-
-  DISALLOW_ALLOCATION();
-  DISALLOW_COPY_AND_ASSIGN(ConditionVariableData);
-};
-
 class MonitorData {
  private:
   MonitorData() {}
diff --git a/runtime/bin/thread_win.cc b/runtime/bin/thread_win.cc
index 2a65586..fea1a63 100644
--- a/runtime/bin/thread_win.cc
+++ b/runtime/bin/thread_win.cc
@@ -106,20 +106,6 @@
   ReleaseSRWLockExclusive(&data_.lock_);
 }
 
-ConditionVariable::ConditionVariable() {
-  InitializeConditionVariable(&data_.cond_);
-}
-
-ConditionVariable::~ConditionVariable() {}
-
-void ConditionVariable::Wait(Mutex* mutex) {
-  SleepConditionVariableSRW(&data_.cond_, &mutex->data_.lock_, INFINITE, 0);
-}
-
-void ConditionVariable::Notify() {
-  WakeConditionVariable(&data_.cond_);
-}
-
 Monitor::Monitor() {
   InitializeCriticalSection(&data_.cs_);
   InitializeConditionVariable(&data_.cond_);
diff --git a/runtime/bin/thread_win.h b/runtime/bin/thread_win.h
index 141e0d0..99691d2 100644
--- a/runtime/bin/thread_win.h
+++ b/runtime/bin/thread_win.h
@@ -25,25 +25,11 @@
   SRWLOCK lock_;
 
   friend class Mutex;
-  friend class ConditionVariable;
 
   DISALLOW_ALLOCATION();
   DISALLOW_COPY_AND_ASSIGN(MutexData);
 };
 
-class ConditionVariableData {
- private:
-  ConditionVariableData() {}
-  ~ConditionVariableData() {}
-
-  CONDITION_VARIABLE cond_;
-
-  friend class ConditionVariable;
-
-  DISALLOW_ALLOCATION();
-  DISALLOW_COPY_AND_ASSIGN(ConditionVariableData);
-};
-
 class MonitorData {
  private:
   MonitorData() {}
diff --git a/runtime/lib/concurrent.cc b/runtime/lib/concurrent.cc
new file mode 100644
index 0000000..1a76eea
--- /dev/null
+++ b/runtime/lib/concurrent.cc
@@ -0,0 +1,101 @@
+// Copyright (c) 2024, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "include/dart_api.h"
+#include "vm/bootstrap_natives.h"
+#include "vm/os_thread.h"
+
+namespace dart {
+
+static void DeleteMutex(void* isolate_data, void* mutex_pointer) {
+  delete reinterpret_cast<Mutex*>(mutex_pointer);
+}
+
+static constexpr int kMutexNativeField = 0;
+
+DEFINE_FFI_NATIVE_ENTRY(Mutex_Initialize, void, (Dart_Handle mutex_handle)) {
+  Mutex* mutex = new Mutex();
+  Dart_Handle err = Dart_SetNativeInstanceField(
+      mutex_handle, kMutexNativeField, reinterpret_cast<intptr_t>(mutex));
+  if (Dart_IsError(err)) {
+    delete mutex;
+    Dart_PropagateError(err);
+  }
+  Dart_NewFinalizableHandle(mutex_handle, mutex, sizeof(Mutex), DeleteMutex);
+};
+
+DEFINE_FFI_NATIVE_ENTRY(Mutex_Lock, void, (Dart_Handle mutex_handle)) {
+  Mutex* mutex;
+  Dart_Handle result = Dart_GetNativeInstanceField(
+      mutex_handle, kMutexNativeField, reinterpret_cast<intptr_t*>(&mutex));
+  if (Dart_IsError(result)) {
+    Dart_PropagateError(result);
+  }
+  mutex->Lock();
+}
+
+DEFINE_FFI_NATIVE_ENTRY(Mutex_Unlock, void, (Dart_Handle mutex_handle)) {
+  Mutex* mutex;
+  Dart_Handle result = Dart_GetNativeInstanceField(
+      mutex_handle, kMutexNativeField, reinterpret_cast<intptr_t*>(&mutex));
+  if (Dart_IsError(result)) {
+    Dart_PropagateError(result);
+  }
+  mutex->Unlock();
+}
+
+static void DeleteConditionVariable(void* isolate_data, void* condvar_pointer) {
+  delete reinterpret_cast<ConditionVariable*>(condvar_pointer);
+}
+
+static constexpr int kCondVarNativeField = 0;
+
+DEFINE_FFI_NATIVE_ENTRY(ConditionVariable_Initialize,
+                        void,
+                        (Dart_Handle condvar_handle)) {
+  ConditionVariable* condvar = new ConditionVariable();
+  Dart_Handle err = Dart_SetNativeInstanceField(
+      condvar_handle, kCondVarNativeField, reinterpret_cast<intptr_t>(condvar));
+  if (Dart_IsError(err)) {
+    delete condvar;
+    Dart_PropagateError(err);
+  }
+  Dart_NewFinalizableHandle(condvar_handle, condvar, sizeof(ConditionVariable),
+                            DeleteConditionVariable);
+}
+
+DEFINE_FFI_NATIVE_ENTRY(ConditionVariable_Wait,
+                        void,
+                        (Dart_Handle condvar_handle,
+                         Dart_Handle mutex_handle)) {
+  Mutex* mutex;
+  Dart_Handle result_mutex = Dart_GetNativeInstanceField(
+      mutex_handle, kCondVarNativeField, reinterpret_cast<intptr_t*>(&mutex));
+  if (Dart_IsError(result_mutex)) {
+    Dart_PropagateError(result_mutex);
+  }
+  ConditionVariable* condvar;
+  Dart_Handle result_condvar =
+      Dart_GetNativeInstanceField(condvar_handle, kCondVarNativeField,
+                                  reinterpret_cast<intptr_t*>(&condvar));
+  if (Dart_IsError(result_condvar)) {
+    Dart_PropagateError(result_condvar);
+  }
+  condvar->Wait(mutex);
+}
+
+DEFINE_FFI_NATIVE_ENTRY(ConditionVariable_Notify,
+                        void,
+                        (Dart_Handle condvar_handle)) {
+  ConditionVariable* condvar;
+  Dart_Handle result_condvar =
+      Dart_GetNativeInstanceField(condvar_handle, kCondVarNativeField,
+                                  reinterpret_cast<intptr_t*>(&condvar));
+  if (Dart_IsError(result_condvar)) {
+    Dart_PropagateError(result_condvar);
+  }
+  condvar->Notify();
+}
+
+}  // namespace dart
diff --git a/runtime/bin/concurrent_impl_sources.gni b/runtime/lib/concurrent_sources.gni
similarity index 80%
rename from runtime/bin/concurrent_impl_sources.gni
rename to runtime/lib/concurrent_sources.gni
index a6f84b2..2f2bad2 100644
--- a/runtime/bin/concurrent_impl_sources.gni
+++ b/runtime/lib/concurrent_sources.gni
@@ -2,4 +2,4 @@
 # for details. All rights reserved. Use of this source code is governed by a
 # BSD-style license that can be found in the LICENSE file.
 
-concurrent_api_sources = [ "concurrent.cc" ]
+concurrent_runtime_cc_files = [ "concurrent.cc" ]
diff --git a/runtime/vm/BUILD.gn b/runtime/vm/BUILD.gn
index b5c6ef5..b0b270fc 100644
--- a/runtime/vm/BUILD.gn
+++ b/runtime/vm/BUILD.gn
@@ -24,6 +24,7 @@
 import("../bin/io_sources.gni")
 import("../configs.gni")
 import("../lib/async_sources.gni")
+import("../lib/concurrent_sources.gni")
 import("../lib/convert_sources.gni")
 import("../lib/core_sources.gni")
 import("../lib/developer_sources.gni")
@@ -222,11 +223,12 @@
     extra_deps += [ "$fuchsia_sdk/pkg/trace-engine" ]
   }
   include_dirs = [ ".." ]
-  allsources = async_runtime_cc_files + core_runtime_cc_files +
-               developer_runtime_cc_files + isolate_runtime_cc_files +
+  allsources = async_runtime_cc_files + concurrent_runtime_cc_files +
+               core_runtime_cc_files + developer_runtime_cc_files +
+               ffi_runtime_cc_files + isolate_runtime_cc_files +
                math_runtime_cc_files + mirrors_runtime_cc_files +
-               typed_data_runtime_cc_files + vmservice_runtime_cc_files +
-               ffi_runtime_cc_files
+               typed_data_runtime_cc_files + vmservice_runtime_cc_files
+
   sources = [ "bootstrap.cc" ] + rebase_path(allsources, ".", "../lib")
   snapshot_sources = []
 }
diff --git a/runtime/vm/bootstrap_natives.cc b/runtime/vm/bootstrap_natives.cc
index 4547b91..cf2184d 100644
--- a/runtime/vm/bootstrap_natives.cc
+++ b/runtime/vm/bootstrap_natives.cc
@@ -117,6 +117,7 @@
   ASSERT(!library.IsNull());
   library.set_native_entry_resolver(resolver);
   library.set_native_entry_symbol_resolver(symbol_resolver);
+  library.set_ffi_native_resolver(ffi_native_resolver);
 
   library = Library::CoreLibrary();
   ASSERT(!library.IsNull());
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index e7853f8..a9fd158 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -366,7 +366,13 @@
   V(VariableMirror_type, 2)
 
 #define BOOTSTRAP_FFI_NATIVE_LIST(V)                                           \
+  V(ConditionVariable_Initialize, void, (Dart_Handle))                         \
+  V(ConditionVariable_Notify, void, (Dart_Handle))                             \
+  V(ConditionVariable_Wait, void, (Dart_Handle, Dart_Handle))                  \
   V(FinalizerEntry_SetExternalSize, void, (Dart_Handle, intptr_t))             \
+  V(Mutex_Initialize, void, (Dart_Handle))                                     \
+  V(Mutex_Lock, void, (Dart_Handle))                                           \
+  V(Mutex_Unlock, void, (Dart_Handle))                                         \
   V(Pointer_asTypedListFinalizerAllocateData, void*, ())                       \
   V(Pointer_asTypedListFinalizerCallbackPointer, void*, ())
 
diff --git a/runtime/vm/os_thread.h b/runtime/vm/os_thread.h
index 2e3fc75..e49977e 100644
--- a/runtime/vm/os_thread.h
+++ b/runtime/vm/os_thread.h
@@ -42,19 +42,23 @@
   explicit Mutex(NOT_IN_PRODUCT(const char* name = "anonymous mutex"));
   ~Mutex();
 
+  ThreadId InvalidateOwner();
+  void SetCurrentThreadAsOwner();
   bool IsOwnedByCurrentThread() const;
 
- private:
   void Lock();
-  bool TryLock();  // Returns false if lock is busy and locking failed.
   void Unlock();
 
+ private:
+  bool TryLock();  // Returns false if lock is busy and locking failed.
+
   MutexData data_;
   NOT_IN_PRODUCT(const char* name_);
 #if defined(DEBUG)
   ThreadId owner_;
 #endif  // defined(DEBUG)
 
+  friend class ConditionVariable;
   friend class MallocLocker;
   friend class MutexLocker;
   friend class SafepointMutexLocker;
@@ -66,6 +70,20 @@
   DISALLOW_COPY_AND_ASSIGN(Mutex);
 };
 
+class ConditionVariable {
+ public:
+  ConditionVariable();
+  ~ConditionVariable();
+
+  void Wait(Mutex* mutex);
+  void Notify();
+
+ private:
+  Mutex* mutex_;
+  ConditionVariableData data_;
+  DISALLOW_COPY_AND_ASSIGN(ConditionVariable);
+};
+
 class BaseThread {
  public:
   bool is_os_thread() const { return is_os_thread_; }
@@ -408,6 +426,24 @@
 #endif
 }
 
+inline ThreadId Mutex::InvalidateOwner() {
+#if defined(DEBUG)
+  ThreadId saved_owner = owner_;
+  owner_ = OSThread::kInvalidThreadId;
+  return saved_owner;
+#else
+  UNREACHABLE();
+#endif
+}
+
+inline void Mutex::SetCurrentThreadAsOwner() {
+#if defined(DEBUG)
+  owner_ = OSThread::GetCurrentThreadId();
+#else
+  UNREACHABLE();
+#endif
+}
+
 // Mark when we are running in a signal handler (Linux, Android) or with a
 // suspended thread (Windows, Mac, Fuchia). During this time, we cannot take
 // locks, access Thread/Isolate::Current(), or use malloc.
diff --git a/runtime/vm/os_thread_absl.cc b/runtime/vm/os_thread_absl.cc
index 8c4e7e2..37d8996 100644
--- a/runtime/vm/os_thread_absl.cc
+++ b/runtime/vm/os_thread_absl.cc
@@ -374,6 +374,27 @@
   data_.mutex()->Unlock();
 }
 
+ConditionVariable::ConditionVariable() {}
+
+ConditionVariable::~ConditionVariable() {}
+
+void ConditionVariable::Wait(Mutex* mutex) {
+#if defined(DEBUG)
+  ThreadId saved_owner = mutex->InvalidateOwner();
+#endif
+
+  data_.cond()->Wait(mutex->data_.mutex());
+
+#if defined(DEBUG)
+  mutex->SetCurrentThreadAsOwner();
+  ASSERT(OSThread::GetCurrentThreadId() == saved_owner);
+#endif
+}
+
+void ConditionVariable::Notify() {
+  data_.cond()->Signal();
+}
+
 Monitor::Monitor() {
 #if defined(DEBUG)
   // When running with assertions enabled we track the owner.
diff --git a/runtime/vm/os_thread_absl.h b/runtime/vm/os_thread_absl.h
index e10793b..9912342 100644
--- a/runtime/vm/os_thread_absl.h
+++ b/runtime/vm/os_thread_absl.h
@@ -50,11 +50,27 @@
   absl::Mutex mutex_;
 
   friend class Mutex;
+  friend class ConditionVariable;
 
   DISALLOW_ALLOCATION();
   DISALLOW_COPY_AND_ASSIGN(MutexData);
 };
 
+class ConditionVariableData {
+ private:
+  ConditionVariableData() : cond_() {}
+  ~ConditionVariableData() {}
+
+  absl::CondVar* cond() { return &cond_; }
+
+  absl::CondVar cond_;
+
+  friend class ConditionVariable;
+
+  DISALLOW_ALLOCATION();
+  DISALLOW_COPY_AND_ASSIGN(ConditionVariableData);
+};
+
 class MonitorData {
  private:
   MonitorData() : mutex_(), cond_() {}
diff --git a/runtime/vm/os_thread_android.cc b/runtime/vm/os_thread_android.cc
index d4ad65a..8937d9c 100644
--- a/runtime/vm/os_thread_android.cc
+++ b/runtime/vm/os_thread_android.cc
@@ -369,6 +369,45 @@
   ASSERT_PTHREAD_SUCCESS(result);  // Verify no other errors.
 }
 
+ConditionVariable::ConditionVariable() {
+  pthread_condattr_t cond_attr;
+  int result = pthread_condattr_init(&cond_attr);
+  VALIDATE_PTHREAD_RESULT(result);
+
+  result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
+  VALIDATE_PTHREAD_RESULT(result);
+
+  result = pthread_cond_init(data_.cond(), &cond_attr);
+  VALIDATE_PTHREAD_RESULT(result);
+
+  result = pthread_condattr_destroy(&cond_attr);
+  VALIDATE_PTHREAD_RESULT(result);
+}
+
+ConditionVariable::~ConditionVariable() {
+  int result = pthread_cond_destroy(data_.cond());
+  VALIDATE_PTHREAD_RESULT(result);
+}
+
+void ConditionVariable::Wait(Mutex* mutex) {
+#if defined(DEBUG)
+  ThreadId saved_owner = mutex->InvalidateOwner();
+#endif
+
+  int result = pthread_cond_wait(data_.cond(), mutex->data_.mutex());
+  VALIDATE_PTHREAD_RESULT(result);
+
+#if defined(DEBUG)
+  mutex->SetCurrentThreadAsOwner();
+  ASSERT(OSThread::GetCurrentThreadId() == saved_owner);
+#endif
+}
+
+void ConditionVariable::Notify() {
+  int result = pthread_cond_signal(data_.cond());
+  VALIDATE_PTHREAD_RESULT(result);
+}
+
 Monitor::Monitor() {
   pthread_mutexattr_t mutex_attr;
   int result = pthread_mutexattr_init(&mutex_attr);
diff --git a/runtime/vm/os_thread_android.h b/runtime/vm/os_thread_android.h
index 9e2e0d0..4474421 100644
--- a/runtime/vm/os_thread_android.h
+++ b/runtime/vm/os_thread_android.h
@@ -49,11 +49,27 @@
   pthread_mutex_t mutex_;
 
   friend class Mutex;
+  friend class ConditionVariable;
 
   DISALLOW_ALLOCATION();
   DISALLOW_COPY_AND_ASSIGN(MutexData);
 };
 
+class ConditionVariableData {
+ private:
+  ConditionVariableData() {}
+  ~ConditionVariableData() {}
+
+  pthread_cond_t* cond() { return &cond_; }
+
+  pthread_cond_t cond_;
+
+  friend class ConditionVariable;
+
+  DISALLOW_ALLOCATION();
+  DISALLOW_COPY_AND_ASSIGN(ConditionVariableData);
+};
+
 class MonitorData {
  private:
   MonitorData() {}
diff --git a/runtime/vm/os_thread_fuchsia.cc b/runtime/vm/os_thread_fuchsia.cc
index c529423..97d7819 100644
--- a/runtime/vm/os_thread_fuchsia.cc
+++ b/runtime/vm/os_thread_fuchsia.cc
@@ -362,6 +362,45 @@
   ASSERT_PTHREAD_SUCCESS(result);  // Verify no other errors.
 }
 
+ConditionVariable::ConditionVariable() {
+  pthread_condattr_t cond_attr;
+  int result = pthread_condattr_init(&cond_attr);
+  VALIDATE_PTHREAD_RESULT(result);
+
+  result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
+  VALIDATE_PTHREAD_RESULT(result);
+
+  result = pthread_cond_init(data_.cond(), &cond_attr);
+  VALIDATE_PTHREAD_RESULT(result);
+
+  result = pthread_condattr_destroy(&cond_attr);
+  VALIDATE_PTHREAD_RESULT(result);
+}
+
+ConditionVariable::~ConditionVariable() {
+  int result = pthread_cond_destroy(data_.cond());
+  VALIDATE_PTHREAD_RESULT(result);
+}
+
+void ConditionVariable::Wait(Mutex* mutex) {
+#if defined(DEBUG)
+  ThreadId saved_owner = mutex->InvalidateOwner();
+#endif
+
+  int result = pthread_cond_wait(data_.cond(), mutex->data_.mutex());
+  VALIDATE_PTHREAD_RESULT(result);
+
+#if defined(DEBUG)
+  mutex->SetCurrentThreadAsOwner();
+  ASSERT(OSThread::GetCurrentThreadId() == saved_owner);
+#endif
+}
+
+void ConditionVariable::Notify() {
+  int result = pthread_cond_signal(data_.cond());
+  VALIDATE_PTHREAD_RESULT(result);
+}
+
 Monitor::Monitor() {
   pthread_mutexattr_t mutex_attr;
   int result = pthread_mutexattr_init(&mutex_attr);
diff --git a/runtime/vm/os_thread_fuchsia.h b/runtime/vm/os_thread_fuchsia.h
index e17b4a6..8df5cb5 100644
--- a/runtime/vm/os_thread_fuchsia.h
+++ b/runtime/vm/os_thread_fuchsia.h
@@ -50,11 +50,27 @@
   pthread_mutex_t mutex_;
 
   friend class Mutex;
+  friend class ConditionVariable;
 
   DISALLOW_ALLOCATION();
   DISALLOW_COPY_AND_ASSIGN(MutexData);
 };
 
+class ConditionVariableData {
+ private:
+  ConditionVariableData() {}
+  ~ConditionVariableData() {}
+
+  pthread_cond_t* cond() { return &cond_; }
+
+  pthread_cond_t cond_;
+
+  friend class ConditionVariable;
+
+  DISALLOW_ALLOCATION();
+  DISALLOW_COPY_AND_ASSIGN(ConditionVariableData);
+};
+
 class MonitorData {
  private:
   MonitorData() {}
diff --git a/runtime/vm/os_thread_linux.cc b/runtime/vm/os_thread_linux.cc
index 3543aaa..ccaa14a 100644
--- a/runtime/vm/os_thread_linux.cc
+++ b/runtime/vm/os_thread_linux.cc
@@ -370,6 +370,45 @@
   ASSERT_PTHREAD_SUCCESS(result);  // Verify no other errors.
 }
 
+ConditionVariable::ConditionVariable() {
+  pthread_condattr_t cond_attr;
+  int result = pthread_condattr_init(&cond_attr);
+  VALIDATE_PTHREAD_RESULT(result);
+
+  result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
+  VALIDATE_PTHREAD_RESULT(result);
+
+  result = pthread_cond_init(data_.cond(), &cond_attr);
+  VALIDATE_PTHREAD_RESULT(result);
+
+  result = pthread_condattr_destroy(&cond_attr);
+  VALIDATE_PTHREAD_RESULT(result);
+}
+
+ConditionVariable::~ConditionVariable() {
+  int result = pthread_cond_destroy(data_.cond());
+  VALIDATE_PTHREAD_RESULT(result);
+}
+
+void ConditionVariable::Wait(Mutex* mutex) {
+#if defined(DEBUG)
+  ThreadId saved_owner = mutex->InvalidateOwner();
+#endif
+
+  int result = pthread_cond_wait(data_.cond(), mutex->data_.mutex());
+  VALIDATE_PTHREAD_RESULT(result);
+
+#if defined(DEBUG)
+  mutex->SetCurrentThreadAsOwner();
+  ASSERT(OSThread::GetCurrentThreadId() == saved_owner);
+#endif
+}
+
+void ConditionVariable::Notify() {
+  int result = pthread_cond_signal(data_.cond());
+  VALIDATE_PTHREAD_RESULT(result);
+}
+
 Monitor::Monitor() {
   pthread_mutexattr_t mutex_attr;
   int result = pthread_mutexattr_init(&mutex_attr);
diff --git a/runtime/vm/os_thread_linux.h b/runtime/vm/os_thread_linux.h
index 9acc2e3..e835af4 100644
--- a/runtime/vm/os_thread_linux.h
+++ b/runtime/vm/os_thread_linux.h
@@ -49,11 +49,27 @@
   pthread_mutex_t mutex_;
 
   friend class Mutex;
+  friend class ConditionVariable;
 
   DISALLOW_ALLOCATION();
   DISALLOW_COPY_AND_ASSIGN(MutexData);
 };
 
+class ConditionVariableData {
+ private:
+  ConditionVariableData() {}
+  ~ConditionVariableData() {}
+
+  pthread_cond_t* cond() { return &cond_; }
+
+  pthread_cond_t cond_;
+
+  friend class ConditionVariable;
+
+  DISALLOW_ALLOCATION();
+  DISALLOW_COPY_AND_ASSIGN(ConditionVariableData);
+};
+
 class MonitorData {
  private:
   MonitorData() {}
diff --git a/runtime/vm/os_thread_macos.cc b/runtime/vm/os_thread_macos.cc
index 0d9c8de..40937c7 100644
--- a/runtime/vm/os_thread_macos.cc
+++ b/runtime/vm/os_thread_macos.cc
@@ -338,6 +338,35 @@
   ASSERT_PTHREAD_SUCCESS(result);  // Verify no other errors.
 }
 
+ConditionVariable::ConditionVariable() {
+  int result = pthread_cond_init(data_.cond(), nullptr);
+  VALIDATE_PTHREAD_RESULT(result);
+}
+
+ConditionVariable::~ConditionVariable() {
+  int result = pthread_cond_destroy(data_.cond());
+  VALIDATE_PTHREAD_RESULT(result);
+}
+
+void ConditionVariable::Wait(Mutex* mutex) {
+#if defined(DEBUG)
+  ThreadId saved_owner = mutex->InvalidateOwner();
+#endif
+
+  int result = pthread_cond_wait(data_.cond(), mutex->data_.mutex());
+  VALIDATE_PTHREAD_RESULT(result);
+
+#if defined(DEBUG)
+  mutex->SetCurrentThreadAsOwner();
+  ASSERT(OSThread::GetCurrentThreadId() == saved_owner);
+#endif
+}
+
+void ConditionVariable::Notify() {
+  int result = pthread_cond_signal(data_.cond());
+  VALIDATE_PTHREAD_RESULT(result);
+}
+
 Monitor::Monitor() {
   pthread_mutexattr_t attr;
   int result = pthread_mutexattr_init(&attr);
diff --git a/runtime/vm/os_thread_macos.h b/runtime/vm/os_thread_macos.h
index 9b053d0..721aa2e 100644
--- a/runtime/vm/os_thread_macos.h
+++ b/runtime/vm/os_thread_macos.h
@@ -50,11 +50,27 @@
   pthread_mutex_t mutex_;
 
   friend class Mutex;
+  friend class ConditionVariable;
 
   DISALLOW_ALLOCATION();
   DISALLOW_COPY_AND_ASSIGN(MutexData);
 };
 
+class ConditionVariableData {
+ private:
+  ConditionVariableData() {}
+  ~ConditionVariableData() {}
+
+  pthread_cond_t* cond() { return &cond_; }
+
+  pthread_cond_t cond_;
+
+  friend class ConditionVariable;
+
+  DISALLOW_ALLOCATION();
+  DISALLOW_COPY_AND_ASSIGN(ConditionVariableData);
+};
+
 class MonitorData {
  private:
   MonitorData() {}
diff --git a/runtime/vm/os_thread_win.cc b/runtime/vm/os_thread_win.cc
index b884c60..e7d9014 100644
--- a/runtime/vm/os_thread_win.cc
+++ b/runtime/vm/os_thread_win.cc
@@ -278,6 +278,29 @@
   ReleaseSRWLockExclusive(&data_.lock_);
 }
 
+ConditionVariable::ConditionVariable() {
+  InitializeConditionVariable(&data_.cond_);
+}
+
+ConditionVariable::~ConditionVariable() {}
+
+void ConditionVariable::Wait(Mutex* mutex) {
+#if defined(DEBUG)
+  ThreadId saved_owner = mutex->InvalidateOwner();
+#endif
+
+  SleepConditionVariableSRW(&data_.cond_, &mutex->data_.lock_, INFINITE, 0);
+
+#if defined(DEBUG)
+  mutex->SetCurrentThreadAsOwner();
+  ASSERT(OSThread::GetCurrentThreadId() == saved_owner);
+#endif
+}
+
+void ConditionVariable::Notify() {
+  WakeConditionVariable(&data_.cond_);
+}
+
 Monitor::Monitor() {
   InitializeSRWLock(&data_.lock_);
   InitializeConditionVariable(&data_.cond_);
diff --git a/runtime/vm/os_thread_win.h b/runtime/vm/os_thread_win.h
index 8e1e917..25a50d0 100644
--- a/runtime/vm/os_thread_win.h
+++ b/runtime/vm/os_thread_win.h
@@ -47,11 +47,25 @@
   SRWLOCK lock_;
 
   friend class Mutex;
+  friend class ConditionVariable;
 
   DISALLOW_ALLOCATION();
   DISALLOW_COPY_AND_ASSIGN(MutexData);
 };
 
+class ConditionVariableData {
+ private:
+  ConditionVariableData() {}
+  ~ConditionVariableData() {}
+
+  CONDITION_VARIABLE cond_;
+
+  friend class ConditionVariable;
+
+  DISALLOW_ALLOCATION();
+  DISALLOW_COPY_AND_ASSIGN(ConditionVariableData);
+};
+
 class MonitorData {
  private:
   MonitorData() {}
diff --git a/sdk/lib/_internal/vm/lib/concurrent_patch.dart b/sdk/lib/_internal/vm/lib/concurrent_patch.dart
index ce3e86f..4c84309 100644
--- a/sdk/lib/_internal/vm/lib/concurrent_patch.dart
+++ b/sdk/lib/_internal/vm/lib/concurrent_patch.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import "dart:_internal" show patch;
+import "dart:ffi" show Handle, Void, Native;
 import "dart:nativewrappers" show NativeFieldWrapperClass1;
 
 @patch
@@ -18,15 +19,15 @@
     _initialize();
   }
 
-  @pragma("vm:external-name", "Mutex_Initialize")
+  @Native<Void Function(Handle)>(symbol: "Mutex_Initialize")
   external void _initialize();
 
   @patch
-  @pragma("vm:external-name", "Mutex_Lock")
+  @Native<Void Function(Handle)>(symbol: "Mutex_Lock")
   external void _lock();
 
   @patch
-  @pragma("vm:external-name", "Mutex_Unlock")
+  @Native<Void Function(Handle)>(symbol: "Mutex_Unlock")
   external void _unlock();
 
   R runLocked<R>(R Function() action) {
@@ -55,14 +56,14 @@
     _initialize();
   }
 
-  @pragma("vm:external-name", "ConditionVariable_Initialize")
+  @Native<Void Function(Handle)>(symbol: "ConditionVariable_Initialize")
   external void _initialize();
 
   @patch
-  @pragma("vm:external-name", "ConditionVariable_Wait")
+  @Native<Void Function(Handle, Handle)>(symbol: "ConditionVariable_Wait")
   external void wait(Mutex mutex);
 
   @patch
-  @pragma("vm:external-name", "ConditionVariable_Notify")
+  @Native<Void Function(Handle)>(symbol: "ConditionVariable_Notify")
   external void notify();
 }