• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_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)23 recursive_timed_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 ( active_ctx == owner_) {
32             ++count_;
33             return true;
34         }
35         if ( nullptr == owner_) {
36             owner_ = active_ctx;
37             count_ = 1;
38             return true;
39         }
40         BOOST_ASSERT( ! active_ctx->wait_is_linked() );
41         active_ctx->wait_link( wait_queue_);
42         active_ctx->twstatus.store( reinterpret_cast< std::intptr_t >( this), std::memory_order_release);
43         // suspend this fiber until notified or timed-out
44         if ( ! active_ctx->wait_until( timeout_time, lk) ) {
45             // remove fiber from wait-queue
46             lk.lock();
47             wait_queue_.remove( * active_ctx);
48             return false;
49         }
50         BOOST_ASSERT( ! active_ctx->wait_is_linked() );
51     }
52 }
53 
54 void
lock()55 recursive_timed_mutex::lock() {
56     while ( true) {
57         context * active_ctx = context::active();
58         // store this fiber in order to be notified later
59         detail::spinlock_lock lk{ wait_queue_splk_ };
60         if ( active_ctx == owner_) {
61             ++count_;
62             return;
63         }
64         if ( nullptr == owner_) {
65             owner_ = active_ctx;
66             count_ = 1;
67             return;
68         }
69         BOOST_ASSERT( ! active_ctx->wait_is_linked() );
70         active_ctx->twstatus.store( static_cast< std::intptr_t >( 0), std::memory_order_release);
71         active_ctx->wait_link( wait_queue_);
72         // suspend this fiber
73         active_ctx->suspend( lk);
74         BOOST_ASSERT( ! active_ctx->wait_is_linked() );
75     }
76 }
77 
78 bool
try_lock()79 recursive_timed_mutex::try_lock() noexcept {
80     context * active_ctx = context::active();
81     detail::spinlock_lock lk{ wait_queue_splk_ };
82     if ( nullptr == owner_) {
83         owner_ = active_ctx;
84         count_ = 1;
85     } else if ( active_ctx == owner_) {
86         ++count_;
87     }
88     lk.unlock();
89     // let other fiber release the lock
90     active_ctx->yield();
91     return active_ctx == owner_;
92 }
93 
94 void
unlock()95 recursive_timed_mutex::unlock() {
96     context * active_ctx = context::active();
97     detail::spinlock_lock lk{ wait_queue_splk_ };
98     if ( BOOST_UNLIKELY( active_ctx != owner_) ) {
99         throw lock_error{
100                 std::make_error_code( std::errc::operation_not_permitted),
101                 "boost fiber: no  privilege to perform the operation" };
102     }
103     if ( 0 == --count_) {
104         owner_ = nullptr;
105         if ( ! wait_queue_.empty() ) {
106             context * ctx = & wait_queue_.front();
107             wait_queue_.pop_front();
108             auto expected = reinterpret_cast< std::intptr_t >( this);
109             if ( ctx->twstatus.compare_exchange_strong( expected, static_cast< std::intptr_t >( -1), std::memory_order_acq_rel) ) {
110                 // notify context
111                 active_ctx->schedule( ctx);
112             } else if ( static_cast< std::intptr_t >( 0) == expected) {
113                 // no timed-wait op.
114                 // notify context
115                 active_ctx->schedule( ctx);
116             }
117         }
118     }
119 }
120 
121 }}
122 
123 #ifdef BOOST_HAS_ABI_HEADERS
124 #  include BOOST_ABI_SUFFIX
125 #endif
126