// 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/dart_api_impl.h" #include "vm/ffi_callback_metadata.h" #include "vm/heap/safepoint.h" #include "vm/os_thread.h" namespace dart { static void DeleteMutex(void* isolate_data, void* mutex_pointer) { delete reinterpret_cast(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(mutex)); if (Dart_IsError(err)) { delete mutex; Dart_PropagateError(err); } Dart_NewFinalizableHandle(mutex_handle, mutex, sizeof(Mutex), DeleteMutex); }; DEFINE_FFI_NATIVE_ENTRY(Mutex_RunLocked, Dart_Handle, (Dart_Handle mutex_handle, Dart_Handle closure_handle)) { Mutex* mutex; Dart_Handle result = Dart_GetNativeInstanceField( mutex_handle, kMutexNativeField, reinterpret_cast(&mutex)); if (Dart_IsError(result)) { Dart_PropagateError(result); } mutex->Lock(); result = Dart_InvokeClosure(closure_handle, 0, nullptr); mutex->Unlock(); if (Dart_IsError(result)) { Dart_PropagateError(result); } return result; } static void DeleteConditionVariable(void* isolate_data, void* condvar_pointer) { delete reinterpret_cast(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(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, intptr_t timeout)) { Mutex* mutex; Dart_Handle result_mutex = Dart_GetNativeInstanceField( mutex_handle, kCondVarNativeField, reinterpret_cast(&mutex)); if (Dart_IsError(result_mutex)) { Dart_PropagateError(result_mutex); } ConditionVariable* condvar; Dart_Handle result_condvar = Dart_GetNativeInstanceField(condvar_handle, kCondVarNativeField, reinterpret_cast(&condvar)); if (Dart_IsError(result_condvar)) { Dart_PropagateError(result_condvar); } condvar->Wait(mutex, timeout); } DEFINE_FFI_NATIVE_ENTRY(ConditionVariable_Notify, void, (Dart_Handle condvar_handle)) { ConditionVariable* condvar; Dart_Handle result_condvar = Dart_GetNativeInstanceField(condvar_handle, kCondVarNativeField, reinterpret_cast(&condvar)); if (Dart_IsError(result_condvar)) { Dart_PropagateError(result_condvar); } condvar->Notify(); } DEFINE_FFI_NATIVE_ENTRY(ConditionVariable_NotifyAll, void, (Dart_Handle condvar_handle)) { ConditionVariable* condvar; Dart_Handle result_condvar = Dart_GetNativeInstanceField(condvar_handle, kCondVarNativeField, reinterpret_cast(&condvar)); if (Dart_IsError(result_condvar)) { Dart_PropagateError(result_condvar); } condvar->NotifyAll(); } DEFINE_FFI_NATIVE_ENTRY(IsolateGroup_runSync, Dart_Handle, (Dart_Handle closure)) { if (!FLAG_experimental_shared_data) { FATAL( "Encountered shared data api when functionality is disabled. " "Pass --experimental-shared-data"); } Thread* current_thread = Thread::Current(); ASSERT(current_thread->execution_state() == Thread::kThreadInNative); { DARTSCOPE(current_thread); FfiCallbackMetadata::EnsureTriviallyImmutable( current_thread->zone(), Object::Handle(Api::UnwrapHandle(closure))); } Isolate* saved_isolate = current_thread->isolate(); current_thread->ExitSafepointFromNative(); current_thread->set_execution_state(Thread::kThreadInVM); Thread::ExitIsolate(/*isolate_shutdown=*/false); Thread::EnterIsolateGroupAsMutator(current_thread->isolate_group(), /*bypass_safepoint=*/false); auto mutator_thread = Thread::Current(); ApiState* state = mutator_thread->isolate_group()->api_state(); ASSERT(state != nullptr); mutator_thread->EnterApiScope(); ASSERT(mutator_thread->execution_state() == Thread::kThreadInVM); Dart_PersistentHandle persistent_result; { TransitionVMToNative transition(mutator_thread); Dart_Handle result = Dart_InvokeClosure(closure, 0, nullptr); persistent_result = Dart_NewPersistentHandle(result); } mutator_thread->ExitApiScope(); Thread::ExitIsolateGroupAsMutator(/*bypass_safepoint=*/false); Thread::EnterIsolate(saved_isolate); Thread* T = Thread::Current(); T->set_execution_state(Thread::kThreadInNative); T->EnterSafepoint(); Dart_Handle local_handle = Dart_HandleFromPersistent(persistent_result); Dart_DeletePersistentHandle(persistent_result); return local_handle; } } // namespace dart