]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | |
23 | timed_mutex::try_lock_until_( std::chrono::steady_clock::time_point const& timeout_time) noexcept { | |
b32b8144 FG |
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_); | |
b32b8144 FG |
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() ); | |
7c673cae | 46 | } |
7c673cae FG |
47 | } |
48 | ||
49 | void | |
50 | timed_mutex::lock() { | |
b32b8144 FG |
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 | } else if ( nullptr == owner_) { | |
60 | owner_ = active_ctx; | |
61 | return; | |
62 | } | |
63 | BOOST_ASSERT( ! active_ctx->wait_is_linked() ); | |
64 | active_ctx->wait_link( wait_queue_); | |
65 | active_ctx->twstatus.store( static_cast< std::intptr_t >( 0), std::memory_order_release); | |
66 | // suspend this fiber | |
67 | active_ctx->suspend( lk); | |
68 | BOOST_ASSERT( ! active_ctx->wait_is_linked() ); | |
7c673cae | 69 | } |
7c673cae FG |
70 | } |
71 | ||
72 | bool | |
73 | timed_mutex::try_lock() { | |
b32b8144 FG |
74 | context * active_ctx = context::active(); |
75 | detail::spinlock_lock lk{ wait_queue_splk_ }; | |
76 | if ( BOOST_UNLIKELY( active_ctx == owner_) ) { | |
77 | throw lock_error{ | |
7c673cae | 78 | std::make_error_code( std::errc::resource_deadlock_would_occur), |
b32b8144 | 79 | "boost fiber: a deadlock is detected" }; |
7c673cae | 80 | } else if ( nullptr == owner_) { |
b32b8144 | 81 | owner_ = active_ctx; |
7c673cae FG |
82 | } |
83 | lk.unlock(); | |
84 | // let other fiber release the lock | |
b32b8144 FG |
85 | active_ctx->yield(); |
86 | return active_ctx == owner_; | |
7c673cae FG |
87 | } |
88 | ||
89 | void | |
90 | timed_mutex::unlock() { | |
b32b8144 FG |
91 | context * active_ctx = context::active(); |
92 | detail::spinlock_lock lk{ wait_queue_splk_ }; | |
93 | if ( BOOST_UNLIKELY( active_ctx != owner_) ) { | |
94 | throw lock_error{ | |
7c673cae | 95 | std::make_error_code( std::errc::operation_not_permitted), |
b32b8144 | 96 | "boost fiber: no privilege to perform the operation" }; |
7c673cae | 97 | } |
b32b8144 | 98 | owner_ = nullptr; |
7c673cae FG |
99 | if ( ! wait_queue_.empty() ) { |
100 | context * ctx = & wait_queue_.front(); | |
101 | wait_queue_.pop_front(); | |
b32b8144 FG |
102 | std::intptr_t expected = reinterpret_cast< std::intptr_t >( this); |
103 | if ( ctx->twstatus.compare_exchange_strong( expected, static_cast< std::intptr_t >( -1), std::memory_order_acq_rel) ) { | |
b32b8144 FG |
104 | // notify context |
105 | active_ctx->schedule( ctx); | |
106 | } else if ( static_cast< std::intptr_t >( 0) == expected) { | |
107 | // no timed-wait op. | |
108 | // notify context | |
109 | active_ctx->schedule( ctx); | |
b32b8144 | 110 | } |
7c673cae FG |
111 | } |
112 | } | |
113 | ||
114 | }} | |
115 | ||
116 | #ifdef BOOST_HAS_ABI_HEADERS | |
117 | # include BOOST_ABI_SUFFIX | |
118 | #endif |