1 use std
::sync
::atomic
::{AtomicBool, AtomicUsize, Ordering}
;
2 use std
::sync
::{Condvar, Mutex}
;
5 use crate::sleep
::Sleep
;
7 /// We define various kinds of latches, which are all a primitive signaling
8 /// mechanism. A latch starts as false. Eventually someone calls `set()` and
9 /// it becomes true. You can test if it has been set by calling `probe()`.
11 /// Some kinds of latches, but not all, support a `wait()` operation
12 /// that will wait until the latch is set, blocking efficiently. That
13 /// is not part of the trait since it is not possibly to do with all
16 /// The intention is that `set()` is called once, but `probe()` may be
17 /// called any number of times. Once `probe()` returns true, the memory
18 /// effects that occurred before `set()` become visible.
20 /// It'd probably be better to refactor the API into two paired types,
21 /// but that's a bit of work, and this is not a public API.
23 /// ## Memory ordering
25 /// Latches need to guarantee two things:
27 /// - Once `probe()` returns true, all memory effects from the `set()`
28 /// are visible (in other words, the set should synchronize-with
30 /// - Once `set()` occurs, the next `probe()` *will* observe it. This
31 /// typically requires a seq-cst ordering. See [the "tickle-then-get-sleepy" scenario in the sleep
32 /// README](/src/sleep/README.md#tickle-then-get-sleepy) for details.
33 pub(super) trait Latch
: LatchProbe
{
34 /// Set the latch, signalling others.
38 pub(super) trait LatchProbe
{
39 /// Test if the latch is set.
40 fn probe(&self) -> bool
;
43 /// Spin latches are the simplest, most efficient kind, but they do
44 /// not support a `wait()` operation. They just have a boolean flag
45 /// that becomes true when `set()` is called.
46 pub(super) struct SpinLatch
{
52 pub(super) fn new() -> SpinLatch
{
54 b
: AtomicBool
::new(false),
59 impl LatchProbe
for SpinLatch
{
61 fn probe(&self) -> bool
{
62 self.b
.load(Ordering
::SeqCst
)
66 impl Latch
for SpinLatch
{
69 self.b
.store(true, Ordering
::SeqCst
);
73 /// A Latch starts as false and eventually becomes true. You can block
74 /// until it becomes true.
75 pub(super) struct LockLatch
{
82 pub(super) fn new() -> LockLatch
{
89 /// Block until latch is set, then resets this lock latch so it can be reused again.
90 pub(super) fn wait_and_reset(&self) {
91 let mut guard
= self.m
.lock().unwrap();
93 guard
= self.v
.wait(guard
).unwrap();
98 /// Block until latch is set.
99 pub(super) fn wait(&self) {
100 let mut guard
= self.m
.lock().unwrap();
102 guard
= self.v
.wait(guard
).unwrap();
107 impl LatchProbe
for LockLatch
{
109 fn probe(&self) -> bool
{
110 // Not particularly efficient, but we don't really use this operation
111 let guard
= self.m
.lock().unwrap();
116 impl Latch
for LockLatch
{
119 let mut guard
= self.m
.lock().unwrap();
125 /// Counting latches are used to implement scopes. They track a
126 /// counter. Unlike other latches, calling `set()` does not
127 /// necessarily make the latch be considered `set()`; instead, it just
128 /// decrements the counter. The latch is only "set" (in the sense that
129 /// `probe()` returns true) once the counter reaches zero.
131 pub(super) struct CountLatch
{
132 counter
: AtomicUsize
,
137 pub(super) fn new() -> CountLatch
{
139 counter
: AtomicUsize
::new(1),
144 pub(super) fn increment(&self) {
145 debug_assert
!(!self.probe());
146 self.counter
.fetch_add(1, Ordering
::Relaxed
);
150 impl LatchProbe
for CountLatch
{
152 fn probe(&self) -> bool
{
153 // Need to acquire any memory reads before latch was set:
154 self.counter
.load(Ordering
::SeqCst
) == 0
158 impl Latch
for CountLatch
{
159 /// Set the latch to true, releasing all threads who are waiting.
162 self.counter
.fetch_sub(1, Ordering
::SeqCst
);
166 /// A tickling latch wraps another latch type, and will also awaken a thread
167 /// pool when it is set. This is useful for jobs injected between thread pools,
168 /// so the source pool can continue processing its own work while waiting.
169 pub(super) struct TickleLatch
<'a
, L
: Latch
> {
174 impl<'a
, L
: Latch
> TickleLatch
<'a
, L
> {
176 pub(super) fn new(latch
: L
, sleep
: &'a Sleep
) -> Self {
184 impl<'a
, L
: Latch
> LatchProbe
for TickleLatch
<'a
, L
> {
186 fn probe(&self) -> bool
{
191 impl<'a
, L
: Latch
> Latch
for TickleLatch
<'a
, L
> {
195 self.sleep
.tickle(usize::MAX
);
199 impl<'a
, L
> LatchProbe
for &'a L
203 fn probe(&self) -> bool
{
208 impl<'a
, L
> Latch
for &'a L