1 use std
::sync
::atomic
::{AtomicBool, AtomicUsize, Ordering}
;
2 use std
::sync
::{Mutex, Condvar}
;
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 trait Latch
: LatchProbe
{
34 /// Set the latch, signalling others.
38 pub 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 struct SpinLatch
{
52 pub fn new() -> SpinLatch
{
53 SpinLatch { b: AtomicBool::new(false) }
57 impl LatchProbe
for SpinLatch
{
59 fn probe(&self) -> bool
{
60 self.b
.load(Ordering
::SeqCst
)
64 impl Latch
for SpinLatch
{
67 self.b
.store(true, Ordering
::SeqCst
);
71 /// A Latch starts as false and eventually becomes true. You can block
72 /// until it becomes true.
73 pub struct LockLatch
{
80 pub fn new() -> LockLatch
{
87 /// Block until latch is set.
89 let mut guard
= self.m
.lock().unwrap();
91 guard
= self.v
.wait(guard
).unwrap();
96 impl LatchProbe
for LockLatch
{
98 fn probe(&self) -> bool
{
99 // Not particularly efficient, but we don't really use this operation
100 let guard
= self.m
.lock().unwrap();
105 impl Latch
for LockLatch
{
108 let mut guard
= self.m
.lock().unwrap();
114 /// Counting latches are used to implement scopes. They track a
115 /// counter. Unlike other latches, calling `set()` does not
116 /// necessarily make the latch be considered `set()`; instead, it just
117 /// decrements the counter. The latch is only "set" (in the sense that
118 /// `probe()` returns true) once the counter reaches zero.
120 pub struct CountLatch
{
121 counter
: AtomicUsize
,
126 pub fn new() -> CountLatch
{
127 CountLatch { counter: AtomicUsize::new(1) }
131 pub fn increment(&self) {
132 debug_assert
!(!self.probe());
133 self.counter
.fetch_add(1, Ordering
::Relaxed
);
137 impl LatchProbe
for CountLatch
{
139 fn probe(&self) -> bool
{
140 // Need to acquire any memory reads before latch was set:
141 self.counter
.load(Ordering
::SeqCst
) == 0
145 impl Latch
for CountLatch
{
146 /// Set the latch to true, releasing all threads who are waiting.
149 self.counter
.fetch_sub(1, Ordering
::SeqCst
);
154 /// A tickling latch wraps another latch type, and will also awaken a thread
155 /// pool when it is set. This is useful for jobs injected between thread pools,
156 /// so the source pool can continue processing its own work while waiting.
157 pub struct TickleLatch
<'a
, L
: Latch
> {
162 impl<'a
, L
: Latch
> TickleLatch
<'a
, L
> {
164 pub fn new(latch
: L
, sleep
: &'a Sleep
) -> Self {
172 impl<'a
, L
: Latch
> LatchProbe
for TickleLatch
<'a
, L
> {
174 fn probe(&self) -> bool
{
179 impl<'a
, L
: Latch
> Latch
for TickleLatch
<'a
, L
> {
183 self.sleep
.tickle(usize::MAX
);