]> git.proxmox.com Git - ceph.git/blame - 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
CommitLineData
b32b8144
FG
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
20effc67 10#include <algorithm>
b32b8144
FG
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
22namespace boost {
23namespace fibers {
24namespace detail {
25
26template< typename FBSplk >
27class spinlock_rtm {
28private:
29 FBSplk splk_{};
30
31public:
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