ecency-mobile/ios/Pods/boost-for-react-native/boost/fiber/condition_variable.hpp

262 lines
8.4 KiB
C++

// Copyright Oliver Kowalke 2013.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_FIBERS_CONDITION_VARIABLE_H
#define BOOST_FIBERS_CONDITION_VARIABLE_H
#include <algorithm>
#include <atomic>
#include <chrono>
#include <functional>
#include <mutex>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/fiber/context.hpp>
#include <boost/fiber/detail/config.hpp>
#include <boost/fiber/detail/convert.hpp>
#include <boost/fiber/detail/spinlock.hpp>
#include <boost/fiber/exceptions.hpp>
#include <boost/fiber/mutex.hpp>
#include <boost/fiber/operations.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
#ifdef _MSC_VER
# pragma warning(push)
//# pragma warning(disable:4251)
#endif
namespace boost {
namespace fibers {
enum class cv_status {
no_timeout = 1,
timeout
};
class BOOST_FIBERS_DECL condition_variable_any {
private:
typedef context::wait_queue_t wait_queue_t;
wait_queue_t wait_queue_{};
detail::spinlock wait_queue_splk_{};
public:
condition_variable_any() = default;
~condition_variable_any() {
BOOST_ASSERT( wait_queue_.empty() );
}
condition_variable_any( condition_variable_any const&) = delete;
condition_variable_any & operator=( condition_variable_any const&) = delete;
void notify_one() noexcept;
void notify_all() noexcept;
template< typename LockType >
void wait( LockType & lt) {
context * ctx = context::active();
// atomically call lt.unlock() and block on *this
// store this fiber in waiting-queue
detail::spinlock_lock lk( wait_queue_splk_);
BOOST_ASSERT( ! ctx->wait_is_linked() );
ctx->wait_link( wait_queue_);
// unlock external lt
lt.unlock();
// suspend this fiber
ctx->suspend( lk);
// relock local lk
lk.lock();
// remove from waiting-queue
ctx->wait_unlink();
// unlock local lk
lk.unlock();
// relock external again before returning
try {
lt.lock();
} catch (...) {
std::terminate();
}
// post-conditions
BOOST_ASSERT( ! ctx->wait_is_linked() );
}
template< typename LockType, typename Pred >
void wait( LockType & lt, Pred pred) {
while ( ! pred() ) {
wait( lt);
}
}
template< typename LockType, typename Clock, typename Duration >
cv_status wait_until( LockType & lt, std::chrono::time_point< Clock, Duration > const& timeout_time_) {
cv_status status = cv_status::no_timeout;
std::chrono::steady_clock::time_point timeout_time(
detail::convert( timeout_time_) );
context * ctx = context::active();
// atomically call lt.unlock() and block on *this
// store this fiber in waiting-queue
detail::spinlock_lock lk( wait_queue_splk_);
BOOST_ASSERT( ! ctx->wait_is_linked() );
ctx->wait_link( wait_queue_);
// unlock external lt
lt.unlock();
// suspend this fiber
if ( ! ctx->wait_until( timeout_time, lk) ) {
status = cv_status::timeout;
}
// relock local lk
lk.lock();
// remove from waiting-queue
ctx->wait_unlink();
// unlock local lk
lk.unlock();
// relock external again before returning
try {
lt.lock();
} catch (...) {
std::terminate();
}
// post-conditions
BOOST_ASSERT( ! ctx->wait_is_linked() );
return status;
}
template< typename LockType, typename Clock, typename Duration, typename Pred >
bool wait_until( LockType & lt,
std::chrono::time_point< Clock, Duration > const& timeout_time, Pred pred) {
while ( ! pred() ) {
if ( cv_status::timeout == wait_until( lt, timeout_time) ) {
return pred();
}
}
return true;
}
template< typename LockType, typename Rep, typename Period >
cv_status wait_for( LockType & lt, std::chrono::duration< Rep, Period > const& timeout_duration) {
return wait_until( lt,
std::chrono::steady_clock::now() + timeout_duration);
}
template< typename LockType, typename Rep, typename Period, typename Pred >
bool wait_for( LockType & lt, std::chrono::duration< Rep, Period > const& timeout_duration, Pred pred) {
return wait_until( lt,
std::chrono::steady_clock::now() + timeout_duration,
pred);
}
};
class BOOST_FIBERS_DECL condition_variable {
private:
condition_variable_any cnd_;
public:
condition_variable() = default;
condition_variable( condition_variable const&) = delete;
condition_variable & operator=( condition_variable const&) = delete;
void notify_one() noexcept {
cnd_.notify_one();
}
void notify_all() noexcept {
cnd_.notify_all();
}
void wait( std::unique_lock< mutex > & lt) {
// pre-condition
BOOST_ASSERT( lt.owns_lock() );
BOOST_ASSERT( context::active() == lt.mutex()->owner_);
cnd_.wait( lt);
// post-condition
BOOST_ASSERT( lt.owns_lock() );
BOOST_ASSERT( context::active() == lt.mutex()->owner_);
}
template< typename Pred >
void wait( std::unique_lock< mutex > & lt, Pred pred) {
// pre-condition
BOOST_ASSERT( lt.owns_lock() );
BOOST_ASSERT( context::active() == lt.mutex()->owner_);
cnd_.wait( lt, pred);
// post-condition
BOOST_ASSERT( lt.owns_lock() );
BOOST_ASSERT( context::active() == lt.mutex()->owner_);
}
template< typename Clock, typename Duration >
cv_status wait_until( std::unique_lock< mutex > & lt,
std::chrono::time_point< Clock, Duration > const& timeout_time) {
// pre-condition
BOOST_ASSERT( lt.owns_lock() );
BOOST_ASSERT( context::active() == lt.mutex()->owner_);
cv_status result = cnd_.wait_until( lt, timeout_time);
// post-condition
BOOST_ASSERT( lt.owns_lock() );
BOOST_ASSERT( context::active() == lt.mutex()->owner_);
return result;
}
template< typename Clock, typename Duration, typename Pred >
bool wait_until( std::unique_lock< mutex > & lt,
std::chrono::time_point< Clock, Duration > const& timeout_time, Pred pred) {
// pre-condition
BOOST_ASSERT( lt.owns_lock() );
BOOST_ASSERT( context::active() == lt.mutex()->owner_);
bool result = cnd_.wait_until( lt, timeout_time, pred);
// post-condition
BOOST_ASSERT( lt.owns_lock() );
BOOST_ASSERT( context::active() == lt.mutex()->owner_);
return result;
}
template< typename Rep, typename Period >
cv_status wait_for( std::unique_lock< mutex > & lt,
std::chrono::duration< Rep, Period > const& timeout_duration) {
// pre-condition
BOOST_ASSERT( lt.owns_lock() );
BOOST_ASSERT( context::active() == lt.mutex()->owner_);
cv_status result = cnd_.wait_for( lt, timeout_duration);
// post-condition
BOOST_ASSERT( lt.owns_lock() );
BOOST_ASSERT( context::active() == lt.mutex()->owner_);
return result;
}
template< typename Rep, typename Period, typename Pred >
bool wait_for( std::unique_lock< mutex > & lt,
std::chrono::duration< Rep, Period > const& timeout_duration, Pred pred) {
// pre-condition
BOOST_ASSERT( lt.owns_lock() );
BOOST_ASSERT( context::active() == lt.mutex()->owner_);
bool result = cnd_.wait_for( lt, timeout_duration, pred);
// post-condition
BOOST_ASSERT( lt.owns_lock() );
BOOST_ASSERT( context::active() == lt.mutex()->owner_);
return result;
}
};
}}
#ifdef _MSC_VER
# pragma warning(pop)
#endif
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif
#endif // BOOST_FIBERS_CONDITION_VARIABLE_H