Skip to content

Commit 73f85a6

Browse files
committed
refactor: unify spawn functions
1 parent 2b52a16 commit 73f85a6

File tree

9 files changed

+461
-559
lines changed

9 files changed

+461
-559
lines changed

Cargo.lock

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ repository = "https://github.com/NthTensor/Forte"
88

99
[workspace]
1010
resolver = "2"
11-
members = ["ci", "rayon-compat"]
11+
members = ["ci"]
1212

1313
[dependencies]
1414
arraydeque = "0.5.1"

rayon-compat/Cargo.toml

Lines changed: 0 additions & 13 deletions
This file was deleted.

rayon-compat/README.md

Lines changed: 0 additions & 14 deletions
This file was deleted.

rayon-compat/src/lib.rs

Lines changed: 0 additions & 186 deletions
This file was deleted.

src/latch.rs

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ const ASLEEP: u32 = 0b10;
2424
// -----------------------------------------------------------------------------
2525
// Latch
2626

27-
/// A [Latch] is a signaling mechanism used to indicate when an event has
27+
/// A Latch is a signaling mechanism used to indicate when an event has
2828
/// occurred. The latch begins as *unset* (In the `LOCKED` state), and can later
29-
/// be *set* by any thread (entering the *SIGNAL*) state.
29+
/// be *set* by any thread (entering the `SIGNAL`) state.
3030
///
3131
/// Each latch is associated with one *owner thread*. This is the thread that
3232
/// may be blocking, waiting for the latch to complete.
@@ -62,10 +62,21 @@ impl Latch {
6262
/// Returns true if the latch signal was received, and false otherwise.
6363
#[inline(always)]
6464
pub fn wait(&self) -> bool {
65+
// First, check if the latch has been set.
66+
//
67+
// In the event of a race with `set`:
68+
// + If this happens before the store, then we will go to sleep.
69+
// + If this happens after the store, then we notice and return.
6570
if self.state.load(Ordering::Relaxed) == SIGNAL {
6671
return true;
6772
}
73+
// If it has not been set, go to sleep.
74+
//
75+
// In the event of a race with `set`, the `wake` will always cause this
76+
// to return regardless of memory ordering.
6877
let slept = self.sleep_controller.sleep();
78+
// If we actually slept, check the status again to see if it has
79+
// changed. Otherwise assume it hasn't.
6980
if slept {
7081
self.state.load(Ordering::Relaxed) == SIGNAL
7182
} else {
@@ -86,8 +97,16 @@ impl Latch {
8697
pub unsafe fn set(latch: *const Latch) {
8798
// SAFETY: At this point, the latch must still be valid to dereference.
8899
let sleep_controller = unsafe { (*latch).sleep_controller };
100+
// First we set the state to true.
101+
//
102+
// In the event of a race with `wait`, this may cause `wait` to return.
103+
// Otherwise the other thread will sleep within `wait.
104+
//
89105
// SAFETY: At this point, the latch must still be valid to dereference.
90106
unsafe { (*latch).state.store(SIGNAL, Ordering::Relaxed) };
107+
// We must try to wake the other thread, just in case it missed the
108+
// notification and went to sleep. This garentees that the other thread
109+
// will make progress.
91110
sleep_controller.wake();
92111
}
93112

@@ -120,21 +139,59 @@ impl Default for SleepController {
120139
}
121140

122141
impl SleepController {
142+
// Attempt to wake the thread to which this belongs.
143+
//
144+
// Returns true if this allows the thread to make progress (by waking it up
145+
// or catching it before it goes to sleep) and false if the thread was
146+
// running.
123147
pub fn wake(&self) -> bool {
148+
// Set set the state to SIGNAL and read the current state, which must be
149+
// either LOCKED or ASLEEP.
124150
let sleep_state = self.state.swap(SIGNAL, Ordering::Relaxed);
125151
let asleep = sleep_state == ASLEEP;
126152
if asleep {
153+
// If the state was ASLEEP, the thread is either asleep or about to
154+
// go to sleep.
155+
//
156+
// + If it is about to go to sleep (but has not yet called
157+
// `atomic_wait::wait`) then setting the state to SIGNAL above
158+
// should prevent it from going to sleep.
159+
//
160+
// + If it is already waiting, the following notification will wake
161+
// it up.
162+
//
163+
// Either way, after this call the other thread must make progress.
127164
atomic_wait::wake_one(&self.state);
128165
}
129166
asleep
130167
}
131168

169+
// Attempt to send the thread to sleep. This should only be called on a
170+
// single thread, and we say that this controller "belongs" to that thread.
171+
//
172+
// Returns true if this thread makes a syscall to suspend the thread, and
173+
// false if the thread was already woken (letting us skip the syscall).
132174
pub fn sleep(&self) -> bool {
175+
// Set the state to ASLEEP and read the current state, which must be
176+
// either LOCKED or SIGNAL.
133177
let state = self.state.swap(ASLEEP, Ordering::Relaxed);
178+
// If the state is LOCKED, then we have not yet received a signal, and
179+
// we should try to put the thread to sleep. Otherwise we should return
180+
// early.
134181
let sleep = state == LOCKED;
135182
if sleep {
183+
// If we have received a signal since entering the sleep state
184+
// (meaning the state is not longer set to ASLEEP) then this will
185+
// return emediately.
186+
//
187+
// If the state is still ASLEEP, then the next call to `wake` will
188+
// register that and call `wake_on`.
189+
//
190+
// Either way, there is no way we can fail to receive a `wake`.
136191
atomic_wait::wait(&self.state, ASLEEP);
137192
}
193+
// Set the state back to LOCKED so that we are ready to receive new
194+
// signals.
138195
self.state.store(LOCKED, Ordering::Relaxed);
139196
sleep
140197
}

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,15 @@ mod util;
4646
// Top-level exports
4747

4848
pub use scope::Scope;
49+
pub use scope::ScopedSpawn;
50+
pub use thread_pool::Spawn;
4951
pub use thread_pool::ThreadPool;
5052
pub use thread_pool::Worker;
5153
pub use thread_pool::Yield;
5254
pub use thread_pool::block_on;
5355
pub use thread_pool::join;
5456
pub use thread_pool::scope;
5557
pub use thread_pool::spawn;
56-
pub use thread_pool::spawn_async;
57-
pub use thread_pool::spawn_future;
5858

5959
// -----------------------------------------------------------------------------
6060
// Platform Support

0 commit comments

Comments
 (0)