blob: c0997198238a27fb01c25e910c4670ded9abc6ec [file] [log] [blame]
// 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_