// 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_PLATFORM_SYNCHRONIZATION_H_ #define RUNTIME_PLATFORM_SYNCHRONIZATION_H_ #include "platform/allocation.h" #include "platform/threads.h" #if defined(DART_USE_ABSL) #include "third_party/absl/synchronization/mutex.h" #endif namespace dart { #if defined(DART_USE_ABSL) using MutexImpl = absl::Mutex; using ConditionVariableImpl = absl::CondVar; #elif defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_FUCHSIA) || \ defined(DART_HOST_OS_MACOS) || defined(DART_HOST_OS_ANDROID) using MutexImpl = pthread_mutex_t; using ConditionVariableImpl = pthread_cond_t; #elif defined(DART_HOST_OS_WINDOWS) using MutexImpl = SRWLOCK; using ConditionVariableImpl = CONDITION_VARIABLE; #else #error Unknown target os. #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. class DisallowMutexLockingScope : public ValueObject { #if defined(DEBUG) public: DisallowMutexLockingScope() { ASSERT(!is_active_); is_active_ = true; } ~DisallowMutexLockingScope() { is_active_ = false; } static bool is_active() { return is_active_; } private: static inline thread_local bool is_active_ = false; #endif // DEBUG }; class Mutex { public: Mutex(); ~Mutex(); bool IsOwnedByCurrentThread() const { return owner_.IsOwnedByCurrentThread(); } void Lock(); bool TryLock(); // Returns false if lock is busy and locking failed. void Unlock(); private: MutexImpl mutex_; platform::ThreadBoundResource owner_; friend class ConditionVariable; DISALLOW_COPY_AND_ASSIGN(Mutex); }; class ConditionVariable { public: enum WaitResult { kNotified, kTimedOut }; static constexpr int64_t kNoTimeout = 0; ConditionVariable(); ~ConditionVariable(); WaitResult Wait(Mutex* mutex, int64_t timeout_millis = kNoTimeout); WaitResult WaitMicros(Mutex* mutex, int64_t timeout_micros = kNoTimeout); void Notify(); void NotifyAll(); private: ConditionVariableImpl cv_; DISALLOW_COPY_AND_ASSIGN(ConditionVariable); }; class Monitor { public: using WaitResult = ConditionVariable::WaitResult; static constexpr WaitResult kNotified = ConditionVariable::kNotified; static constexpr WaitResult kTimedOut = ConditionVariable::kTimedOut; static constexpr int64_t kNoTimeout = ConditionVariable::kNoTimeout; Monitor() {} ~Monitor() {} bool IsOwnedByCurrentThread() const { return mutex_.IsOwnedByCurrentThread(); } bool TryEnter() { return mutex_.TryLock(); } void Enter() { return mutex_.Lock(); } void Exit() { return mutex_.Unlock(); } // Wait for notification or timeout. WaitResult Wait(int64_t timeout_millis) { return cv_.Wait(&mutex_, timeout_millis); } WaitResult WaitMicros(int64_t timeout_micros) { return cv_.WaitMicros(&mutex_, timeout_micros); } // Notify waiting threads. void Notify() { cv_.Notify(); } void NotifyAll() { cv_.NotifyAll(); } private: Mutex mutex_; // OS-specific data. ConditionVariable cv_; DISALLOW_COPY_AND_ASSIGN(Monitor); }; } // namespace dart #endif // RUNTIME_PLATFORM_SYNCHRONIZATION_H_