mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Automatically generated by https://github.com/flutter/engine/pull/48903. Progress towards https://github.com/flutter/flutter/issues/133415.
274 lines
8.8 KiB
C++
274 lines
8.8 KiB
C++
// Copyright 2013 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#ifndef FLUTTER_IMPELLER_BASE_THREAD_H_
|
|
#define FLUTTER_IMPELLER_BASE_THREAD_H_
|
|
|
|
#include <chrono>
|
|
#include <condition_variable>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <thread>
|
|
|
|
#include "flutter/fml/logging.h"
|
|
#include "flutter/fml/macros.h"
|
|
#include "flutter/fml/synchronization/shared_mutex.h"
|
|
#include "impeller/base/thread_safety.h"
|
|
|
|
namespace impeller {
|
|
|
|
class ConditionVariable;
|
|
|
|
class IPLR_CAPABILITY("mutex") Mutex {
|
|
public:
|
|
Mutex() = default;
|
|
|
|
~Mutex() = default;
|
|
|
|
void Lock() IPLR_ACQUIRE() { mutex_.lock(); }
|
|
|
|
void Unlock() IPLR_RELEASE() { mutex_.unlock(); }
|
|
|
|
private:
|
|
friend class ConditionVariable;
|
|
|
|
std::mutex mutex_;
|
|
|
|
Mutex(const Mutex&) = delete;
|
|
|
|
Mutex(Mutex&&) = delete;
|
|
|
|
Mutex& operator=(const Mutex&) = delete;
|
|
|
|
Mutex& operator=(Mutex&&) = delete;
|
|
};
|
|
|
|
class IPLR_CAPABILITY("mutex") RWMutex {
|
|
public:
|
|
RWMutex()
|
|
: mutex_(std::unique_ptr<fml::SharedMutex>(fml::SharedMutex::Create())) {}
|
|
|
|
~RWMutex() = default;
|
|
|
|
void LockWriter() IPLR_ACQUIRE() { mutex_->Lock(); }
|
|
|
|
void UnlockWriter() IPLR_RELEASE() { mutex_->Unlock(); }
|
|
|
|
void LockReader() IPLR_ACQUIRE_SHARED() { mutex_->LockShared(); }
|
|
|
|
void UnlockReader() IPLR_RELEASE_SHARED() { mutex_->UnlockShared(); }
|
|
|
|
private:
|
|
std::unique_ptr<fml::SharedMutex> mutex_;
|
|
|
|
RWMutex(const RWMutex&) = delete;
|
|
|
|
RWMutex(RWMutex&&) = delete;
|
|
|
|
RWMutex& operator=(const RWMutex&) = delete;
|
|
|
|
RWMutex& operator=(RWMutex&&) = delete;
|
|
};
|
|
|
|
class IPLR_SCOPED_CAPABILITY Lock {
|
|
public:
|
|
explicit Lock(Mutex& mutex) IPLR_ACQUIRE(mutex) : mutex_(mutex) {
|
|
mutex_.Lock();
|
|
}
|
|
|
|
~Lock() IPLR_RELEASE() { mutex_.Unlock(); }
|
|
|
|
private:
|
|
Mutex& mutex_;
|
|
|
|
Lock(const Lock&) = delete;
|
|
|
|
Lock(Lock&&) = delete;
|
|
|
|
Lock& operator=(const Lock&) = delete;
|
|
|
|
Lock& operator=(Lock&&) = delete;
|
|
};
|
|
|
|
class IPLR_SCOPED_CAPABILITY ReaderLock {
|
|
public:
|
|
explicit ReaderLock(RWMutex& mutex) IPLR_ACQUIRE_SHARED(mutex)
|
|
: mutex_(mutex) {
|
|
mutex_.LockReader();
|
|
}
|
|
|
|
~ReaderLock() IPLR_RELEASE() { mutex_.UnlockReader(); }
|
|
|
|
private:
|
|
RWMutex& mutex_;
|
|
|
|
ReaderLock(const ReaderLock&) = delete;
|
|
|
|
ReaderLock(ReaderLock&&) = delete;
|
|
|
|
ReaderLock& operator=(const ReaderLock&) = delete;
|
|
|
|
ReaderLock& operator=(ReaderLock&&) = delete;
|
|
};
|
|
|
|
class IPLR_SCOPED_CAPABILITY WriterLock {
|
|
public:
|
|
explicit WriterLock(RWMutex& mutex) IPLR_ACQUIRE(mutex) : mutex_(mutex) {
|
|
mutex_.LockWriter();
|
|
}
|
|
|
|
~WriterLock() IPLR_RELEASE() { mutex_.UnlockWriter(); }
|
|
|
|
private:
|
|
RWMutex& mutex_;
|
|
|
|
WriterLock(const WriterLock&) = delete;
|
|
|
|
WriterLock(WriterLock&&) = delete;
|
|
|
|
WriterLock& operator=(const WriterLock&) = delete;
|
|
|
|
WriterLock& operator=(WriterLock&&) = delete;
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// @brief A condition variable exactly similar to the one in libcxx with
|
|
/// two major differences:
|
|
///
|
|
/// * On the Wait, WaitFor, and WaitUntil calls, static analysis
|
|
/// annotation are respected.
|
|
/// * There is no ability to wait on a condition variable and also
|
|
/// be susceptible to spurious wakes. This is because the
|
|
/// predicate is mandatory.
|
|
///
|
|
class ConditionVariable {
|
|
public:
|
|
ConditionVariable() = default;
|
|
|
|
~ConditionVariable() = default;
|
|
|
|
ConditionVariable(const ConditionVariable&) = delete;
|
|
|
|
ConditionVariable& operator=(const ConditionVariable&) = delete;
|
|
|
|
void NotifyOne() { cv_.notify_one(); }
|
|
|
|
void NotifyAll() { cv_.notify_all(); }
|
|
|
|
using Predicate = std::function<bool()>;
|
|
|
|
//----------------------------------------------------------------------------
|
|
/// @brief Atomically unlocks the mutex and waits on the condition
|
|
/// variable up to a specified time point. Lock will be reacquired
|
|
/// when the wait exits. Spurious wakes may happen before the time
|
|
/// point is reached. In such cases the predicate is invoked and
|
|
/// it must return `false` for the wait to continue. The predicate
|
|
/// will be invoked with the mutex locked.
|
|
///
|
|
/// @note Since the predicate is invoked with the mutex locked, if it
|
|
/// accesses other guarded resources, the predicate itself must be
|
|
/// decorated with the IPLR_REQUIRES directive. For instance,
|
|
///
|
|
/// ```c++
|
|
/// [] () IPLR_REQUIRES(mutex) {
|
|
/// return my_guarded_resource.should_stop_waiting;
|
|
/// }
|
|
/// ```
|
|
///
|
|
/// @param mutex The mutex.
|
|
/// @param[in] time_point The time point to wait to.
|
|
/// @param[in] should_stop_waiting The predicate invoked on spurious wakes.
|
|
/// Must return false for the wait to
|
|
/// continue.
|
|
///
|
|
/// @tparam Clock The clock type.
|
|
/// @tparam Duration The duration type.
|
|
///
|
|
/// @return The value of the predicate at the end of the wait.
|
|
///
|
|
template <class Clock, class Duration>
|
|
bool WaitUntil(Mutex& mutex,
|
|
const std::chrono::time_point<Clock, Duration>& time_point,
|
|
const Predicate& should_stop_waiting) IPLR_REQUIRES(mutex) {
|
|
std::unique_lock lock(mutex.mutex_, std::adopt_lock);
|
|
const auto result = cv_.wait_until(lock, time_point, should_stop_waiting);
|
|
lock.release();
|
|
return result;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
/// @brief Atomically unlocks the mutex and waits on the condition
|
|
/// variable for a designated duration. Lock will be reacquired
|
|
/// when the wait exits. Spurious wakes may happen before the time
|
|
/// point is reached. In such cases the predicate is invoked and
|
|
/// it must return `false` for the wait to continue. The predicate
|
|
/// will be invoked with the mutex locked.
|
|
///
|
|
/// @note Since the predicate is invoked with the mutex locked, if it
|
|
/// accesses other guarded resources, the predicate itself must be
|
|
/// decorated with the IPLR_REQUIRES directive. For instance,
|
|
///
|
|
/// ```c++
|
|
/// [] () IPLR_REQUIRES(mutex) {
|
|
/// return my_guarded_resource.should_stop_waiting;
|
|
/// }
|
|
/// ```
|
|
///
|
|
/// @param mutex The mutex.
|
|
/// @param[in] duration The duration to wait for.
|
|
/// @param[in] should_stop_waiting The predicate invoked on spurious wakes.
|
|
/// Must return false for the wait to
|
|
/// continue.
|
|
///
|
|
/// @tparam Representation The duration representation type.
|
|
/// @tparam Period The duration period type.
|
|
///
|
|
/// @return The value of the predicate at the end of the wait.
|
|
///
|
|
template <class Representation, class Period>
|
|
bool WaitFor(Mutex& mutex,
|
|
const std::chrono::duration<Representation, Period>& duration,
|
|
const Predicate& should_stop_waiting) IPLR_REQUIRES(mutex) {
|
|
return WaitUntil(mutex, std::chrono::steady_clock::now() + duration,
|
|
should_stop_waiting);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
/// @brief Atomically unlocks the mutex and waits on the condition
|
|
/// variable indefinitely till the predicate determines that the
|
|
/// wait must end. Lock will be reacquired when the wait exits.
|
|
/// Spurious wakes may happen before the time point is reached. In
|
|
/// such cases the predicate is invoked and it must return `false`
|
|
/// for the wait to continue. The predicate will be invoked with
|
|
/// the mutex locked.
|
|
///
|
|
/// @note Since the predicate is invoked with the mutex locked, if it
|
|
/// accesses other guarded resources, the predicate itself must be
|
|
/// decorated with the IPLR_REQUIRES directive. For instance,
|
|
///
|
|
/// ```c++
|
|
/// [] () IPLR_REQUIRES(mutex) {
|
|
/// return my_guarded_resource.should_stop_waiting;
|
|
/// }
|
|
/// ```
|
|
///
|
|
/// @param mutex The mutex
|
|
/// @param[in] should_stop_waiting The should stop waiting
|
|
///
|
|
void Wait(Mutex& mutex, const Predicate& should_stop_waiting)
|
|
IPLR_REQUIRES(mutex) {
|
|
std::unique_lock lock(mutex.mutex_, std::adopt_lock);
|
|
cv_.wait(lock, should_stop_waiting);
|
|
lock.release();
|
|
}
|
|
|
|
private:
|
|
std::condition_variable cv_;
|
|
};
|
|
|
|
} // namespace impeller
|
|
|
|
#endif // FLUTTER_IMPELLER_BASE_THREAD_H_
|