1 2 // Copyright Oliver Kowalke 2013. 3 // Distributed under the Boost Software License, Version 1.0. 4 // (See accompanying file LICENSE_1_0.txt or copy at 5 // http://www.boost.org/LICENSE_1_0.txt) 6 7 #include "boost/fiber/timed_mutex.hpp" 8 9 #include <algorithm> 10 #include <functional> 11 12 #include "boost/fiber/exceptions.hpp" 13 #include "boost/fiber/scheduler.hpp" 14 15 #ifdef BOOST_HAS_ABI_HEADERS 16 # include BOOST_ABI_PREFIX 17 #endif 18 19 namespace boost { 20 namespace fibers { 21 22 bool try_lock_until_(std::chrono::steady_clock::time_point const & timeout_time)23timed_mutex::try_lock_until_( std::chrono::steady_clock::time_point const& timeout_time) noexcept { 24 while ( true) { 25 if ( std::chrono::steady_clock::now() > timeout_time) { 26 return false; 27 } 28 context * active_ctx = context::active(); 29 // store this fiber in order to be notified later 30 detail::spinlock_lock lk{ wait_queue_splk_ }; 31 if ( nullptr == owner_) { 32 owner_ = active_ctx; 33 return true; 34 } 35 BOOST_ASSERT( ! active_ctx->wait_is_linked() ); 36 active_ctx->wait_link( wait_queue_); 37 active_ctx->twstatus.store( reinterpret_cast< std::intptr_t >( this), std::memory_order_release); 38 // suspend this fiber until notified or timed-out 39 if ( ! active_ctx->wait_until( timeout_time, lk) ) { 40 // remove fiber from wait-queue 41 lk.lock(); 42 wait_queue_.remove( * active_ctx); 43 return false; 44 } 45 BOOST_ASSERT( ! active_ctx->wait_is_linked() ); 46 } 47 } 48 49 void lock()50timed_mutex::lock() { 51 while ( true) { 52 context * active_ctx = context::active(); 53 // store this fiber in order to be notified later 54 detail::spinlock_lock lk{ wait_queue_splk_ }; 55 if ( BOOST_UNLIKELY( active_ctx == owner_) ) { 56 throw lock_error{ 57 std::make_error_code( std::errc::resource_deadlock_would_occur), 58 "boost fiber: a deadlock is detected" }; 59 } 60 if ( nullptr == owner_) { 61 owner_ = active_ctx; 62 return; 63 } 64 BOOST_ASSERT( ! active_ctx->wait_is_linked() ); 65 active_ctx->wait_link( wait_queue_); 66 active_ctx->twstatus.store( static_cast< std::intptr_t >( 0), std::memory_order_release); 67 // suspend this fiber 68 active_ctx->suspend( lk); 69 BOOST_ASSERT( ! active_ctx->wait_is_linked() ); 70 } 71 } 72 73 bool try_lock()74timed_mutex::try_lock() { 75 context * active_ctx = context::active(); 76 detail::spinlock_lock lk{ wait_queue_splk_ }; 77 if ( BOOST_UNLIKELY( active_ctx == owner_) ) { 78 throw lock_error{ 79 std::make_error_code( std::errc::resource_deadlock_would_occur), 80 "boost fiber: a deadlock is detected" }; 81 } 82 if ( nullptr == owner_) { 83 owner_ = active_ctx; 84 } 85 lk.unlock(); 86 // let other fiber release the lock 87 active_ctx->yield(); 88 return active_ctx == owner_; 89 } 90 91 void unlock()92timed_mutex::unlock() { 93 context * active_ctx = context::active(); 94 detail::spinlock_lock lk{ wait_queue_splk_ }; 95 if ( BOOST_UNLIKELY( active_ctx != owner_) ) { 96 throw lock_error{ 97 std::make_error_code( std::errc::operation_not_permitted), 98 "boost fiber: no privilege to perform the operation" }; 99 } 100 owner_ = nullptr; 101 if ( ! wait_queue_.empty() ) { 102 context * ctx = & wait_queue_.front(); 103 wait_queue_.pop_front(); 104 auto expected = reinterpret_cast< std::intptr_t >( this); 105 if ( ctx->twstatus.compare_exchange_strong( expected, static_cast< std::intptr_t >( -1), std::memory_order_acq_rel) ) { 106 // notify context 107 active_ctx->schedule( ctx); 108 } else if ( static_cast< std::intptr_t >( 0) == expected) { 109 // no timed-wait op. 110 // notify context 111 active_ctx->schedule( ctx); 112 } 113 } 114 } 115 116 }} 117 118 #ifdef BOOST_HAS_ABI_HEADERS 119 # include BOOST_ABI_SUFFIX 120 #endif 121