• 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/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 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 ( 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()50 timed_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()74 timed_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()92 timed_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