Skip to content

Commit 6c2b11c

Browse files
committed
Safety comments
1 parent 2d8bca2 commit 6c2b11c

File tree

2 files changed

+52
-2
lines changed

2 files changed

+52
-2
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ futures-lite = { version = "2.0.0", default-features = false, features = ["std"]
3636
async-channel = "2.0.0"
3737
async-io = "2.1.0"
3838
async-lock = "3.0.0"
39-
criterion = { version = "0.7", default-features = false, features = ["cargo_bench_support"] }
39+
criterion = { version = "0.5", default-features = false, features = ["cargo_bench_support"] }
4040
easy-parallel = "3.1.0"
4141
fastrand = "2.0.0"
4242
futures-lite = "2.0.0"

src/local_executor.rs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ impl<'a> LocalExecutor<'a> {
8383
/// assert!(local_ex.is_empty());
8484
/// ```
8585
pub fn is_empty(&self) -> bool {
86+
// SAFETY: All UnsafeCell accesses to active are tightly scoped, and because
87+
// `LocalExecutor` is !Send, there is no way to have concurrent access to the
88+
// values in `State`, including the active field.
8689
unsafe { &*self.state().active.get() }.is_empty()
8790
}
8891

@@ -100,6 +103,9 @@ impl<'a> LocalExecutor<'a> {
100103
/// });
101104
/// ```
102105
pub fn spawn<T: 'a>(&self, future: impl Future<Output = T> + 'a) -> Task<T> {
106+
// SAFETY: All UnsafeCell accesses to active are tightly scoped, and because
107+
// `LocalExecutor` is !Send, there is no way to have concurrent access to the
108+
// values in `State`, including the active field.
103109
let active = unsafe { &mut *self.state().active.get() };
104110
self.spawn_inner(future, active)
105111
}
@@ -149,6 +155,9 @@ impl<'a> LocalExecutor<'a> {
149155
futures: impl IntoIterator<Item = F>,
150156
handles: &mut impl Extend<Task<F::Output>>,
151157
) {
158+
// SAFETY: All UnsafeCell accesses to active are tightly scoped, and because
159+
// `LocalExecutor` is !Send, there is no way to have concurrent access to the
160+
// values in `State`, including the active field.
152161
let active = unsafe { &mut *self.state().active.get() };
153162

154163
// Convert the futures into tasks.
@@ -171,6 +180,9 @@ impl<'a> LocalExecutor<'a> {
171180
let index = entry.key();
172181
let state = self.state_as_rc();
173182
let future = AsyncCallOnDrop::new(future, move || {
183+
// SAFETY: All UnsafeCell accesses to active are tightly scoped, and because
184+
// `LocalExecutor` is !Send, there is no way to have concurrent access to the
185+
// values in `State`, including the active field.
174186
drop(unsafe { &mut *state.active.get() }.try_remove(index))
175187
});
176188

@@ -276,9 +288,11 @@ impl<'a> LocalExecutor<'a> {
276288
fn schedule(&self) -> impl Fn(Runnable) + 'static {
277289
let state = self.state_as_rc();
278290

279-
// TODO: If possible, push into the current local queue and notify the ticker.
280291
move |runnable| {
281292
{
293+
// SAFETY: All UnsafeCell accesses to queue are tightly scoped, and because
294+
// `LocalExecutor` is !Send, there is no way to have concurrent access to the
295+
// values in `State`, including the queue field.
282296
let queue = unsafe { &mut *state.queue.get() };
283297
queue.push_front(runnable);
284298
}
@@ -337,12 +351,18 @@ impl Drop for LocalExecutor<'_> {
337351
let state = unsafe { Rc::from_raw(ptr) };
338352

339353
{
354+
// SAFETY: All UnsafeCell accesses to active are tightly scoped, and because
355+
// `LocalExecutor` is !Send, there is no way to have concurrent access to the
356+
// values in `State`, including the active field.
340357
let active = unsafe { &mut *state.active.get() };
341358
for w in active.drain() {
342359
w.wake();
343360
}
344361
}
345362

363+
// SAFETY: All UnsafeCell accesses to queue are tightly scoped, and because
364+
// `LocalExecutor` is !Send, there is no way to have concurrent access to the
365+
// values in `State`, including the queue field.
346366
unsafe { &mut *state.queue.get() }.clear();
347367
}
348368
}
@@ -382,13 +402,19 @@ impl State {
382402
/// Notifies a sleeping ticker.
383403
#[inline]
384404
pub(crate) fn notify(&self) {
405+
// SAFETY: All UnsafeCell accesses to sleepers are tightly scoped, and because
406+
// `LocalExecutor` is !Send, there is no way to have concurrent access to the
407+
// values in `State`, including the sleepers field.
385408
let waker = unsafe { &mut *self.sleepers.get() }.notify();
386409
if let Some(w) = waker {
387410
w.wake();
388411
}
389412
}
390413

391414
pub(crate) fn try_tick(&self) -> bool {
415+
// SAFETY: All UnsafeCell accesses to queue are tightly scoped, and because
416+
// `LocalExecutor` is !Send, there is no way to have concurrent access to the
417+
// values in `State`, including the queue field.
392418
let runnable = unsafe { &mut *self.queue.get() }.pop_back();
393419
match runnable {
394420
None => false,
@@ -449,12 +475,18 @@ impl Ticker<'_> {
449475
match self.sleeping {
450476
// Move to sleeping state.
451477
0 => {
478+
// SAFETY: All UnsafeCell accesses to sleepers are tightly scoped, and because
479+
// `LocalExecutor` is !Send, there is no way to have concurrent access to the
480+
// values in `State`, including the sleepers field.
452481
let sleepers = unsafe { &mut *self.state.sleepers.get() };
453482
self.sleeping = sleepers.insert(waker);
454483
}
455484

456485
// Already sleeping, check if notified.
457486
id => {
487+
// SAFETY: All UnsafeCell accesses to sleepers are tightly scoped, and because
488+
// `LocalExecutor` is !Send, there is no way to have concurrent access to the
489+
// values in `State`, including the sleepers field.
458490
let sleepers = unsafe { &mut *self.state.sleepers.get() };
459491
if !sleepers.update(id, waker) {
460492
return false;
@@ -468,6 +500,9 @@ impl Ticker<'_> {
468500
/// Moves the ticker into woken state.
469501
fn wake(&mut self) {
470502
if self.sleeping != 0 {
503+
// SAFETY: All UnsafeCell accesses to sleepers are tightly scoped, and because
504+
// `LocalExecutor` is !Send, there is no way to have concurrent access to the
505+
// values in `State`, including the sleepers field.
471506
let sleepers = unsafe { &mut *self.state.sleepers.get() };
472507
sleepers.remove(self.sleeping);
473508
}
@@ -478,6 +513,9 @@ impl Ticker<'_> {
478513
async fn runnable(&mut self) -> Runnable {
479514
future::poll_fn(|cx| {
480515
loop {
516+
// SAFETY: All UnsafeCell accesses to queue are tightly scoped, and because
517+
// `LocalExecutor` is !Send, there is no way to have concurrent access to the
518+
// values in `State`, including the queue field.
481519
match unsafe { &mut *self.state.queue.get() }.pop_back() {
482520
None => {
483521
// Move to sleeping and unnotified state.
@@ -504,6 +542,9 @@ impl Drop for Ticker<'_> {
504542
// If this ticker is in sleeping state, it must be removed from the sleepers list.
505543
if self.sleeping != 0 {
506544
let notified = {
545+
// SAFETY: All UnsafeCell accesses to sleepers are tightly scoped, and because
546+
// `LocalExecutor` is !Send, there is no way to have concurrent access to the
547+
// values in `State`, including the sleepers field.
507548
let sleepers = unsafe { &mut *self.state.sleepers.get() };
508549
sleepers.remove(self.sleeping)
509550
};
@@ -552,6 +593,9 @@ pub(crate) fn debug_state(state: &State, name: &str, f: &mut fmt::Formatter<'_>)
552593

553594
impl fmt::Debug for ActiveTasks<'_> {
554595
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
596+
// SAFETY: All UnsafeCell accesses to active are tightly scoped, and because
597+
// `LocalExecutor` is !Send, there is no way to have concurrent access to the
598+
// values in `State`, including the active field.
555599
let active = unsafe { &*self.0.get() };
556600
fmt::Debug::fmt(&active.len(), f)
557601
}
@@ -562,13 +606,19 @@ pub(crate) fn debug_state(state: &State, name: &str, f: &mut fmt::Formatter<'_>)
562606

563607
impl fmt::Debug for SleepCount<'_> {
564608
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
609+
// SAFETY: All UnsafeCell accesses to sleepers are tightly scoped, and because
610+
// `LocalExecutor` is !Send, there is no way to have concurrent access to the
611+
// values in `State`, including the sleepers field.
565612
let sleepers = unsafe { &*self.0.get() };
566613
fmt::Debug::fmt(&sleepers.count, f)
567614
}
568615
}
569616

570617
f.debug_struct(name)
571618
.field("active", &ActiveTasks(&state.active))
619+
// SAFETY: All UnsafeCell accesses to queue are tightly scoped, and because
620+
// `LocalExecutor` is !Send, there is no way to have concurrent access to the
621+
// values in `State`, including the queue field.
572622
.field("global_tasks", &unsafe { &*state.queue.get() }.len())
573623
.field("sleepers", &SleepCount(&state.sleepers))
574624
.finish()

0 commit comments

Comments
 (0)