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/mutex.hpp" 8 9 #include <algorithm> 10 #include <functional> 11 #include <system_error> 12 13 #include "boost/fiber/exceptions.hpp" 14 #include "boost/fiber/scheduler.hpp" 15 16 #ifdef BOOST_HAS_ABI_HEADERS 17 # include BOOST_ABI_PREFIX 18 #endif 19 20 namespace boost { 21 namespace fibers { 22 23 void lock()24mutex::lock() { 25 while ( true) { 26 context * active_ctx = context::active(); 27 // store this fiber in order to be notified later 28 detail::spinlock_lock lk{ wait_queue_splk_ }; 29 if ( BOOST_UNLIKELY( active_ctx == owner_) ) { 30 throw lock_error{ 31 std::make_error_code( std::errc::resource_deadlock_would_occur), 32 "boost fiber: a deadlock is detected" }; 33 } 34 if ( nullptr == owner_) { 35 owner_ = active_ctx; 36 return; 37 } 38 BOOST_ASSERT( ! active_ctx->wait_is_linked() ); 39 active_ctx->wait_link( wait_queue_); 40 // suspend this fiber 41 active_ctx->suspend( lk); 42 BOOST_ASSERT( ! active_ctx->wait_is_linked() ); 43 } 44 } 45 46 bool try_lock()47mutex::try_lock() { 48 context * active_ctx = context::active(); 49 detail::spinlock_lock lk{ wait_queue_splk_ }; 50 if ( BOOST_UNLIKELY( active_ctx == owner_) ) { 51 throw lock_error{ 52 std::make_error_code( std::errc::resource_deadlock_would_occur), 53 "boost fiber: a deadlock is detected" }; 54 } 55 if ( nullptr == owner_) { 56 owner_ = active_ctx; 57 } 58 lk.unlock(); 59 // let other fiber release the lock 60 active_ctx->yield(); 61 return active_ctx == owner_; 62 } 63 64 void unlock()65mutex::unlock() { 66 context * active_ctx = context::active(); 67 detail::spinlock_lock lk{ wait_queue_splk_ }; 68 if ( BOOST_UNLIKELY( active_ctx != owner_) ) { 69 throw lock_error{ 70 std::make_error_code( std::errc::operation_not_permitted), 71 "boost fiber: no privilege to perform the operation" }; 72 } 73 owner_ = nullptr; 74 if ( ! wait_queue_.empty() ) { 75 context * ctx = & wait_queue_.front(); 76 wait_queue_.pop_front(); 77 active_ctx->schedule( ctx); 78 } 79 } 80 81 }} 82 83 #ifdef BOOST_HAS_ABI_HEADERS 84 # include BOOST_ABI_SUFFIX 85 #endif 86