xrpld
Toggle main menu visibility
Loading...
Searching...
No Matches
include
xrpl
basics
spinlock.h
1
// Copyright (c) 2022, Nikolaos D. Bougalis <nikb@bougalis.net>
2
3
#pragma once
4
5
#include <xrpl/beast/utility/instrumentation.h>
6
7
#include <
atomic
>
8
#include <
limits
>
9
#include <
type_traits
>
10
11
#ifndef __aarch64__
12
#include <immintrin.h>
13
#endif
14
15
namespace
xrpl
{
16
17
namespace
detail
{
29
inline
void
30
spinPause
() noexcept
31
{
32
#ifdef __aarch64__
33
asm
volatile
(
"yield"
);
34
#else
35
_mm_pause();
36
#endif
37
}
38
39
}
// namespace detail
40
69
76
template
<
class
T>
77
class
PackedSpinlock
78
{
79
// clang-format off
80
static_assert
(
std::is_unsigned_v<T>
);
81
static_assert
(
std::atomic<T>::is_always_lock_free
);
82
static_assert
(
83
std::is_same_v
<
decltype
(
std::declval<std::atomic<T>
&>().fetch_or(0)), T> &&
84
std::is_same_v
<
decltype
(
std::declval
<
std::atomic<T>
&>().fetch_and(0)), T>,
85
"std::atomic<T>::fetch_and(T) and std::atomic<T>::fetch_and(T) are required by packed_spinlock"
);
86
// clang-format on
87
88
private
:
89
std::atomic<T>
&
bits_
;
90
T
const
mask_
;
91
92
public
:
93
PackedSpinlock
(
PackedSpinlock
const
&) =
delete
;
94
PackedSpinlock
&
95
operator=
(
PackedSpinlock
const
&) =
delete
;
96
106
PackedSpinlock
(
std::atomic<T>
&
lock
,
int
index) :
bits_
(
lock
),
mask_
(static_cast<T>(1) << index)
107
{
108
XRPL_ASSERT(
109
index >= 0 && (
mask_
!= 0),
110
"xrpl::PackedSpinlock::PackedSpinlock : valid index and mask"
);
111
}
112
113
[[nodiscard]]
bool
114
try_lock
()
// NOLINT(readability-identifier-naming)
115
{
116
return
(
bits_
.fetch_or(
mask_
, std::memory_order_acquire) &
mask_
) == 0;
117
}
118
119
void
120
lock
()
121
{
122
while
(!
try_lock
())
123
{
124
// The use of relaxed memory ordering here is intentional and
125
// serves to help reduce cache coherency traffic during times
126
// of contention by avoiding writes that would definitely not
127
// result in the lock being acquired.
128
while
((
bits_
.load(std::memory_order_relaxed) &
mask_
) != 0)
129
detail::spinPause
();
130
}
131
}
132
133
void
134
unlock
()
135
{
136
bits_
.fetch_and(~
mask_
, std::memory_order_release);
137
}
138
};
139
153
template
<
class
T>
154
class
Spinlock
155
{
156
static_assert
(
std::is_unsigned_v<T>
);
157
static_assert
(
std::atomic<T>::is_always_lock_free
);
158
159
private
:
160
std::atomic<T>
&
lock_
;
161
162
public
:
163
Spinlock
(
Spinlock
const
&) =
delete
;
164
Spinlock
&
165
operator=
(
Spinlock
const
&) =
delete
;
166
175
Spinlock
(
std::atomic<T>
&
lock
) :
lock_
(
lock
)
176
{
177
}
178
179
[[nodiscard]]
bool
180
try_lock
()
// NOLINT(readability-identifier-naming)
181
{
182
T expected = 0;
183
184
return
lock_
.compare_exchange_weak(
185
expected,
186
std::numeric_limits<T>::max
(),
187
std::memory_order_acquire,
188
std::memory_order_relaxed);
189
}
190
191
void
192
lock
()
193
{
194
while
(!
try_lock
())
195
{
196
// The use of relaxed memory ordering here is intentional and
197
// serves to help reduce cache coherency traffic during times
198
// of contention by avoiding writes that would definitely not
199
// result in the lock being acquired.
200
while
(
lock_
.load(std::memory_order_relaxed) != 0)
201
detail::spinPause
();
202
}
203
}
204
205
void
206
unlock
()
207
{
208
lock_
.store(0, std::memory_order_release);
209
}
210
};
211
212
213
}
// namespace xrpl
atomic
xrpl::PackedSpinlock::PackedSpinlock
PackedSpinlock(PackedSpinlock const &)=delete
xrpl::PackedSpinlock::bits_
std::atomic< T > & bits_
Definition
spinlock.h:89
xrpl::PackedSpinlock::lock
void lock()
Definition
spinlock.h:120
xrpl::PackedSpinlock::PackedSpinlock
PackedSpinlock(std::atomic< T > &lock, int index)
A single spinlock packed inside the specified atomic.
Definition
spinlock.h:106
xrpl::PackedSpinlock::try_lock
bool try_lock()
Definition
spinlock.h:114
xrpl::PackedSpinlock::unlock
void unlock()
Definition
spinlock.h:134
xrpl::PackedSpinlock::mask_
T const mask_
Definition
spinlock.h:90
xrpl::PackedSpinlock::operator=
PackedSpinlock & operator=(PackedSpinlock const &)=delete
xrpl::Spinlock::Spinlock
Spinlock(Spinlock const &)=delete
xrpl::Spinlock::unlock
void unlock()
Definition
spinlock.h:206
xrpl::Spinlock::Spinlock
Spinlock(std::atomic< T > &lock)
Grabs the.
Definition
spinlock.h:175
xrpl::Spinlock::lock_
std::atomic< T > & lock_
Definition
spinlock.h:160
xrpl::Spinlock::lock
void lock()
Definition
spinlock.h:192
xrpl::Spinlock::operator=
Spinlock & operator=(Spinlock const &)=delete
xrpl::Spinlock::try_lock
bool try_lock()
Definition
spinlock.h:180
std::declval
T declval(T... args)
std::is_same_v
T is_same_v
std::is_unsigned_v
T is_unsigned_v
limits
std::numeric_limits::max
T max(T... args)
xrpl::detail
Definition
base_uint.h:37
xrpl::detail::spinPause
void spinPause() noexcept
Inform the processor that we are in a tight spin-wait loop.
Definition
spinlock.h:30
xrpl
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition
algorithm.h:5
type_traits
Generated by
1.17.0