Imported Upstream version 1.64.0
[platform/upstream/boost.git] / libs / fiber / src / recursive_timed_mutex.cpp
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
23 recursive_timed_mutex::try_lock_until_( std::chrono::steady_clock::time_point const& timeout_time) noexcept {
24     if ( std::chrono::steady_clock::now() > timeout_time) {
25         return false;
26     }
27     context * active_ctx = context::active();
28     // store this fiber in order to be notified later
29     detail::spinlock_lock lk{ wait_queue_splk_ };
30     if ( active_ctx == owner_) {
31         ++count_;
32         return true;
33     } else if ( nullptr == owner_) {
34         owner_ = active_ctx;
35         count_ = 1;
36         return true;
37     }
38     BOOST_ASSERT( ! active_ctx->wait_is_linked() );
39     active_ctx->wait_link( wait_queue_);
40     // suspend this fiber until notified or timed-out
41     if ( ! active_ctx->wait_until( timeout_time, lk) ) {
42         // remove fiber from wait-queue 
43         lk.lock();
44         wait_queue_.remove( * active_ctx);
45         return false;
46     }
47     BOOST_ASSERT( ! active_ctx->wait_is_linked() );
48     return active_ctx == owner_;
49 }
50
51 void
52 recursive_timed_mutex::lock() {
53     context * active_ctx = context::active();
54     // store this fiber in order to be notified later
55     detail::spinlock_lock lk{ wait_queue_splk_ };
56     if ( active_ctx == owner_) {
57         ++count_;
58         return;
59     } else if ( nullptr == owner_) {
60         owner_ = active_ctx;
61         count_ = 1;
62         return;
63     }
64     BOOST_ASSERT( ! active_ctx->wait_is_linked() );
65     active_ctx->wait_link( wait_queue_);
66     // suspend this fiber
67     active_ctx->suspend( lk);
68     BOOST_ASSERT( ! active_ctx->wait_is_linked() );
69 }
70
71 bool
72 recursive_timed_mutex::try_lock() noexcept {
73     context * active_ctx = context::active();
74     detail::spinlock_lock lk{ wait_queue_splk_ };
75     if ( nullptr == owner_) {
76         owner_ = active_ctx;
77         count_ = 1;
78     } else if ( active_ctx == owner_) {
79         ++count_;
80     }
81     lk.unlock();
82     // let other fiber release the lock
83     active_ctx->yield();
84     return active_ctx == owner_;
85 }
86
87 void
88 recursive_timed_mutex::unlock() {
89     context * active_ctx = context::active();
90     detail::spinlock_lock lk{ wait_queue_splk_ };
91     if ( active_ctx != owner_) {
92         throw lock_error{
93                 std::make_error_code( std::errc::operation_not_permitted),
94                 "boost fiber: no  privilege to perform the operation" };
95     }
96     if ( 0 == --count_) {
97         if ( ! wait_queue_.empty() ) {
98             context * ctx = & wait_queue_.front();
99             wait_queue_.pop_front();
100             owner_ = ctx;
101             count_ = 1;
102             active_ctx->schedule( ctx);
103         } else {
104             owner_ = nullptr;
105             return;
106         }
107     }
108 }
109
110 }}
111
112 #ifdef BOOST_HAS_ABI_HEADERS
113 #  include BOOST_ABI_SUFFIX
114 #endif