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/recursive_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 void lock()23recursive_mutex::lock() { 24 while ( true) { 25 context * active_ctx = context::active(); 26 // store this fiber in order to be notified later 27 detail::spinlock_lock lk{ wait_queue_splk_ }; 28 if ( active_ctx == owner_) { 29 ++count_; 30 return; 31 } 32 if ( nullptr == owner_) { 33 owner_ = active_ctx; 34 count_ = 1; 35 return; 36 } 37 BOOST_ASSERT( ! active_ctx->wait_is_linked() ); 38 active_ctx->wait_link( wait_queue_); 39 // suspend this fiber 40 active_ctx->suspend( lk); 41 BOOST_ASSERT( ! active_ctx->wait_is_linked() ); 42 } 43 } 44 45 bool try_lock()46recursive_mutex::try_lock() noexcept { 47 context * active_ctx = context::active(); 48 detail::spinlock_lock lk{ wait_queue_splk_ }; 49 if ( nullptr == owner_) { 50 owner_ = active_ctx; 51 count_ = 1; 52 } else if ( active_ctx == owner_) { 53 ++count_; 54 } 55 lk.unlock(); 56 // let other fiber release the lock 57 context::active()->yield(); 58 return active_ctx == owner_; 59 } 60 61 void unlock()62recursive_mutex::unlock() { 63 context * active_ctx = context::active(); 64 detail::spinlock_lock lk( wait_queue_splk_); 65 if ( BOOST_UNLIKELY( active_ctx != owner_) ) { 66 throw lock_error( 67 std::make_error_code( std::errc::operation_not_permitted), 68 "boost fiber: no privilege to perform the operation"); 69 } 70 if ( 0 == --count_) { 71 owner_ = nullptr; 72 if ( ! wait_queue_.empty() ) { 73 context * ctx = & wait_queue_.front(); 74 wait_queue_.pop_front(); 75 active_ctx->schedule( ctx); 76 } 77 } 78 } 79 80 }} 81 82 #ifdef BOOST_HAS_ABI_HEADERS 83 # include BOOST_ABI_SUFFIX 84 #endif 85