]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/fiber/detail/spinlock_rtm.hpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / boost / fiber / detail / spinlock_rtm.hpp
1
2 // Copyright Oliver Kowalke 2017.
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 #ifndef BOOST_FIBERS_SPINLOCK_RTM_H
8 #define BOOST_FIBERS_SPINLOCK_RTM_H
9
10 #include <algorithm>
11 #include <atomic>
12 #include <chrono>
13 #include <cmath>
14 #include <random>
15 #include <thread>
16
17 #include <boost/fiber/detail/config.hpp>
18 #include <boost/fiber/detail/cpu_relax.hpp>
19 #include <boost/fiber/detail/rtm.hpp>
20 #include <boost/fiber/detail/spinlock_status.hpp>
21
22 namespace boost {
23 namespace fibers {
24 namespace detail {
25
26 template< typename FBSplk >
27 class spinlock_rtm {
28 private:
29 FBSplk splk_{};
30
31 public:
32 spinlock_rtm() = default;
33
34 spinlock_rtm( spinlock_rtm const&) = delete;
35 spinlock_rtm & operator=( spinlock_rtm const&) = delete;
36
37 void lock() noexcept {
38 static thread_local std::minstd_rand generator{ std::random_device{}() };
39 std::size_t collisions = 0 ;
40 for ( std::size_t retries = 0; retries < BOOST_FIBERS_RETRY_THRESHOLD; ++retries) {
41 std::uint32_t status;
42 if ( rtm_status::success == ( status = rtm_begin() ) ) {
43 // add lock to read-set
44 if ( spinlock_status::unlocked == splk_.state_.load( std::memory_order_relaxed) ) {
45 // lock is free, enter critical section
46 return;
47 }
48 // lock was acquired by another thread
49 // explicit abort of transaction with abort argument 'lock not free'
50 rtm_abort_lock_not_free();
51 }
52 // transaction aborted
53 if ( rtm_status::none != (status & rtm_status::may_retry) ||
54 rtm_status::none != (status & rtm_status::memory_conflict) ) {
55 // another logical processor conflicted with a memory address that was
56 // part or the read-/write-set
57 if ( BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD > collisions) {
58 std::uniform_int_distribution< std::size_t > distribution{
59 0, static_cast< std::size_t >( 1) << (std::min)(collisions, static_cast< std::size_t >( BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD)) };
60 const std::size_t z = distribution( generator);
61 ++collisions;
62 for ( std::size_t i = 0; i < z; ++i) {
63 cpu_relax();
64 }
65 } else {
66 std::this_thread::yield();
67 }
68 } else if ( rtm_status::none != (status & rtm_status::explicit_abort) &&
69 rtm_status::none == (status & rtm_status::nested_abort) ) {
70 // another logical processor has acquired the lock and
71 // abort was not caused by a nested transaction
72 // wait till lock becomes free again
73 std::size_t count = 0;
74 while ( spinlock_status::locked == splk_.state_.load( std::memory_order_relaxed) ) {
75 if ( BOOST_FIBERS_SPIN_BEFORE_SLEEP0 > count) {
76 ++count;
77 cpu_relax();
78 } else if ( BOOST_FIBERS_SPIN_BEFORE_YIELD > count) {
79 ++count;
80 static constexpr std::chrono::microseconds us0{ 0 };
81 std::this_thread::sleep_for( us0);
82 #if 0
83 using namespace std::chrono_literals;
84 std::this_thread::sleep_for( 0ms);
85 #endif
86 } else {
87 std::this_thread::yield();
88 }
89 }
90 } else {
91 // transaction aborted due:
92 // - internal buffer to track transactional state overflowed
93 // - debug exception or breakpoint exception was hit
94 // - abort during execution of nested transactions (max nesting limit exceeded)
95 // -> use fallback path
96 break;
97 }
98 }
99 splk_.lock();
100 }
101
102 bool try_lock() noexcept {
103 if ( rtm_status::success != rtm_begin() ) {
104 return false;
105 }
106
107 // add lock to read-set
108 if ( spinlock_status::unlocked != splk_.state_.load( std::memory_order_relaxed) ) {
109 // lock was acquired by another thread
110 // explicit abort of transaction with abort argument 'lock not free'
111 rtm_abort_lock_not_free();
112 }
113 return true;
114 }
115
116 void unlock() noexcept {
117 if ( spinlock_status::unlocked == splk_.state_.load( std::memory_order_acquire) ) {
118 rtm_end();
119 } else {
120 splk_.unlock();
121 }
122 }
123 };
124
125 }}}
126
127 #endif // BOOST_FIBERS_SPINLOCK_RTM_H