Skip to content

Commit 1ec136a

Browse files
committed
Unsplit the 'Incomplete' commit
1 parent 3fefa6c commit 1ec136a

File tree

5 files changed

+304
-179
lines changed

5 files changed

+304
-179
lines changed

src/lib.rs

Lines changed: 77 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
//! }
6161
//! ```
6262
63-
#![cfg_attr(not(feature = "std"), no_std)]
63+
#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
6464
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
6565

6666
extern crate alloc;
@@ -69,7 +69,7 @@ extern crate alloc;
6969
#[cfg_attr(not(feature = "std"), path = "no_std.rs")]
7070
mod sys;
7171

72-
use alloc::sync::Arc;
72+
use alloc::boxed::Box;
7373

7474
use core::borrow::Borrow;
7575
use core::fmt;
@@ -79,15 +79,23 @@ use core::mem::ManuallyDrop;
7979
use core::pin::Pin;
8080
use core::ptr;
8181
use core::task::{Context, Poll, Waker};
82-
use core::usize;
8382

84-
use sync::atomic::{self, AtomicPtr, AtomicUsize, Ordering};
85-
86-
#[cfg(feature = "std")]
87-
use std::panic::{RefUnwindSafe, UnwindSafe};
8883
#[cfg(feature = "std")]
8984
use std::time::{Duration, Instant};
9085

86+
use sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
87+
use sync::{Arc, WithMut};
88+
89+
/// 1.39-compatible replacement for `matches!`
90+
macro_rules! matches {
91+
($expr:expr, $($pattern:pat)|+ $(if $guard: expr)?) => {
92+
match $expr {
93+
$($pattern)|+ $(if $guard)? => true,
94+
_ => false,
95+
}
96+
};
97+
}
98+
9199
/// Inner state of [`Event`].
92100
struct Inner {
93101
/// The number of notified entries, or `usize::MAX` if all of them have been notified.
@@ -96,11 +104,14 @@ struct Inner {
96104
notified: AtomicUsize,
97105

98106
/// Inner queue of event listeners.
107+
///
108+
/// On `std` platforms, this is an intrusive linked list. On `no_std` platforms, this is a
109+
/// more traditional `Vec` of listeners, with an atomic queue used as a backup for high
110+
/// contention.
99111
list: sys::List,
100112
}
101113

102114
impl Inner {
103-
/// Create a new `Inner`.
104115
fn new() -> Self {
105116
Self {
106117
notified: AtomicUsize::new(core::usize::MAX),
@@ -137,10 +148,26 @@ pub struct Event {
137148
inner: AtomicPtr<Inner>,
138149
}
139150

151+
unsafe impl Send for Event {}
152+
unsafe impl Sync for Event {}
153+
140154
#[cfg(feature = "std")]
141-
impl UnwindSafe for Event {}
155+
impl std::panic::UnwindSafe for Event {}
142156
#[cfg(feature = "std")]
143-
impl RefUnwindSafe for Event {}
157+
impl std::panic::RefUnwindSafe for Event {}
158+
159+
impl fmt::Debug for Event {
160+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161+
f.write_str("Pad { .. }")
162+
}
163+
}
164+
165+
impl Default for Event {
166+
#[inline]
167+
fn default() -> Self {
168+
Self::new()
169+
}
170+
}
144171

145172
impl Event {
146173
/// Creates a new [`Event`].
@@ -153,15 +180,17 @@ impl Event {
153180
/// let event = Event::new();
154181
/// ```
155182
#[inline]
156-
pub const fn new() -> Event {
157-
Event {
183+
pub const fn new() -> Self {
184+
Self {
158185
inner: AtomicPtr::new(ptr::null_mut()),
159186
}
160187
}
161188

162189
/// Returns a guard listening for a notification.
163190
///
164-
/// This method emits a `SeqCst` fence after registering a listener.
191+
/// This method emits a `SeqCst` fence after registering a listener. For now, this method
192+
/// is an alias for calling [`EventListener::new()`], pinning it to the heap, and then
193+
/// inserting it into a list.
165194
///
166195
/// # Examples
167196
///
@@ -260,7 +289,7 @@ impl Event {
260289
// Notify if there is at least one unnotified listener and the number of notified
261290
// listeners is less than `n`.
262291
if inner.notified.load(Ordering::Acquire) < n {
263-
inner.notify(n, false);
292+
inner.notify(n, true);
264293
}
265294
}
266295
}
@@ -302,7 +331,7 @@ impl Event {
302331

303332
if let Some(inner) = self.try_inner() {
304333
// Notify if there is at least one unnotified listener.
305-
if inner.notified.load(Ordering::Acquire) < usize::MAX {
334+
if inner.notified.load(Ordering::Acquire) < core::usize::MAX {
306335
inner.notify(n, true);
307336
}
308337
}
@@ -347,34 +376,35 @@ impl Event {
347376
pub fn notify_additional_relaxed(&self, n: usize) {
348377
if let Some(inner) = self.try_inner() {
349378
// Notify if there is at least one unnotified listener.
350-
if inner.notified.load(Ordering::Acquire) < usize::MAX {
379+
if inner.notified.load(Ordering::Acquire) < core::usize::MAX {
351380
inner.notify(n, true);
352381
}
353382
}
354383
}
355384

356-
/// Returns a reference to the inner state if it was initialized.
385+
/// Return a reference to the inner state if it has been initialized.
357386
#[inline]
358387
fn try_inner(&self) -> Option<&Inner> {
359388
let inner = self.inner.load(Ordering::Acquire);
360389
unsafe { inner.as_ref() }
361390
}
362391

363-
/// Returns a raw pointer to the inner state, initializing it if necessary.
392+
/// Returns a raw, initialized pointer to the inner state.
364393
///
365394
/// This returns a raw pointer instead of reference because `from_raw`
366-
/// requires raw/mut provenance: <https://github.com/rust-lang/rust/pull/67339>
395+
/// requires raw/mut provenance: <https://github.com/rust-lang/rust/pull/67339>.
367396
fn inner(&self) -> *const Inner {
368397
let mut inner = self.inner.load(Ordering::Acquire);
369398

370-
// Initialize the state if this is its first use.
399+
// If this is the first use, initialize the state.
371400
if inner.is_null() {
372-
// Allocate on the heap.
401+
// Allocate the state on the heap.
373402
let new = Arc::new(Inner::new());
374-
// Convert the heap-allocated state into a raw pointer.
403+
404+
// Convert the state to a raw pointer.
375405
let new = Arc::into_raw(new) as *mut Inner;
376406

377-
// Attempt to replace the null-pointer with the new state pointer.
407+
// Replace the null pointer with the new state pointer.
378408
inner = self
379409
.inner
380410
.compare_exchange(inner, new, Ordering::AcqRel, Ordering::Acquire)
@@ -400,26 +430,14 @@ impl Event {
400430
impl Drop for Event {
401431
#[inline]
402432
fn drop(&mut self) {
403-
let inner: *mut Inner = *self.inner.get_mut();
404-
405-
// If the state pointer has been initialized, deallocate it.
406-
if !inner.is_null() {
407-
unsafe {
408-
drop(Arc::from_raw(inner));
433+
self.inner.with_mut(|&mut inner| {
434+
// If the state pointer has been initialized, drop it.
435+
if !inner.is_null() {
436+
unsafe {
437+
drop(Arc::from_raw(inner));
438+
}
409439
}
410-
}
411-
}
412-
}
413-
414-
impl fmt::Debug for Event {
415-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
416-
f.pad("Event { .. }")
417-
}
418-
}
419-
420-
impl Default for Event {
421-
fn default() -> Event {
422-
Event::new()
440+
})
423441
}
424442
}
425443

@@ -770,40 +788,35 @@ impl<B: Borrow<Inner> + Unpin> Drop for Listener<B> {
770788

771789
/// The state of a listener.
772790
#[derive(Debug, PartialEq)]
773-
pub(crate) enum State {
774-
/// It has just been created.
791+
enum State {
792+
/// The listener was just created.
775793
Created,
776794

777-
/// It has received a notification.
795+
/// The listener has received a notification.
778796
///
779797
/// The `bool` is `true` if this was an "additional" notification.
780798
Notified(bool),
781799

782-
/// A task is polling it.
800+
/// A task is waiting for a notification.
783801
Task(Task),
784802

785803
/// Empty hole used to replace a notified listener.
786804
NotifiedTaken,
787805
}
788806

789807
impl State {
790-
/// Returns `true` if this is the `Notified` state.
791-
#[inline]
792-
pub(crate) fn is_notified(&self) -> bool {
793-
match self {
794-
State::Notified(_) | Self::NotifiedTaken => true,
795-
_ => false,
796-
}
808+
fn is_notified(&self) -> bool {
809+
matches!(self, Self::Notified(_) | Self::NotifiedTaken)
797810
}
798811
}
799812

800-
/// An asynchronous waker or thread unparker that can be used to notify a task or thread.
801-
#[derive(Debug)]
813+
/// A task that can be woken up.
814+
#[derive(Debug, Clone)]
802815
enum Task {
803-
/// A waker that can be used to notify a task.
816+
/// A waker that wakes up a future.
804817
Waker(Waker),
805818

806-
/// An unparker that can be used to notify a thread.
819+
/// An unparker that wakes up a thread.
807820
#[cfg(feature = "std")]
808821
Unparker(parking::Unparker),
809822
}
@@ -817,12 +830,11 @@ impl Task {
817830
}
818831
}
819832

820-
/// Notifies the task or thread.
821833
fn wake(self) {
822834
match self {
823-
Task::Waker(waker) => waker.wake(),
835+
Self::Waker(waker) => waker.wake(),
824836
#[cfg(feature = "std")]
825-
Task::Unparker(unparker) => {
837+
Self::Unparker(unparker) => {
826838
unparker.unpark();
827839
}
828840
}
@@ -836,7 +848,7 @@ impl PartialEq for Task {
836848
}
837849

838850
/// A reference to a task.
839-
#[derive(Debug, Clone, Copy)]
851+
#[derive(Clone, Copy)]
840852
enum TaskRef<'a> {
841853
/// A waker that wakes up a future.
842854
Waker(&'a Waker),
@@ -890,23 +902,21 @@ fn full_fence() {
890902
// The ideal solution here would be to use inline assembly, but we're instead creating a
891903
// temporary atomic variable and compare-and-exchanging its value. No sane compiler to
892904
// x86 platforms is going to optimize this away.
893-
atomic::compiler_fence(Ordering::SeqCst);
905+
sync::atomic::compiler_fence(Ordering::SeqCst);
894906
let a = AtomicUsize::new(0);
895907
let _ = a.compare_exchange(0, 1, Ordering::SeqCst, Ordering::SeqCst);
896-
atomic::compiler_fence(Ordering::SeqCst);
908+
sync::atomic::compiler_fence(Ordering::SeqCst);
897909
} else {
898-
atomic::fence(Ordering::SeqCst);
910+
sync::atomic::fence(Ordering::SeqCst);
899911
}
900912
}
901913

902914
/// Synchronization primitive implementation.
903915
mod sync {
916+
pub(super) use alloc::sync::Arc;
904917
pub(super) use core::cell;
905918
pub(super) use core::sync::atomic;
906919

907-
#[cfg(not(feature = "std"))]
908-
pub(super) use alloc::sync::Arc;
909-
910920
#[cfg(feature = "std")]
911921
pub(super) use std::sync::{Mutex, MutexGuard};
912922

src/no_std/node.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
//! An operation that can be delayed.
2+
13
//! The node that makes up queues.
24
3-
use super::ListenerSlab;
45
use crate::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
56
use crate::sync::Arc;
7+
use crate::sys::ListenerSlab;
68
use crate::{State, Task};
79

810
use alloc::boxed::Box;
@@ -32,7 +34,7 @@ pub(crate) enum Node {
3234
/// This node is removing a listener.
3335
RemoveListener {
3436
/// The ID of the listener to remove.
35-
key: NonZeroUsize,
37+
listener: NonZeroUsize,
3638

3739
/// Whether to propagate notifications to the next listener.
3840
propagate: bool,
@@ -42,6 +44,7 @@ pub(crate) enum Node {
4244
Waiting(Task),
4345
}
4446

47+
#[derive(Debug)]
4548
pub(crate) struct TaskWaiting {
4649
/// The task that is being waited on.
4750
task: AtomicCell<Task>,
@@ -69,23 +72,27 @@ impl Node {
6972
}
7073

7174
/// Apply the node to the list.
72-
pub(crate) fn apply(self, list: &mut ListenerSlab) -> Option<Task> {
75+
pub(super) fn apply(self, list: &mut ListenerSlab) -> Option<Task> {
7376
match self {
7477
Node::AddListener { task_waiting } => {
7578
// Add a new entry to the list.
7679
let key = list.insert(State::Created);
7780

7881
// Send the new key to the listener and wake it if necessary.
7982
task_waiting.entry_id.store(key.get(), Ordering::Release);
83+
8084
return task_waiting.task.take().map(|t| *t);
8185
}
8286
Node::Notify { count, additional } => {
83-
// Notify the listener.
87+
// Notify the next `count` listeners.
8488
list.notify(count, additional);
8589
}
86-
Node::RemoveListener { key, propagate } => {
90+
Node::RemoveListener {
91+
listener,
92+
propagate,
93+
} => {
8794
// Remove the listener from the list.
88-
list.remove(key, propagate);
95+
list.remove(listener, propagate);
8996
}
9097
Node::Waiting(task) => {
9198
return Some(task);

0 commit comments

Comments
 (0)