| // 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_ |