Skip to content

Commit 7349ce6

Browse files
authored
Unrolled build for rust-lang#118960
Rollup merge of rust-lang#118960 - tvallotton:local_waker, r=Mark-Simulacrum Add LocalWaker and ContextBuilder types to core, and LocalWake trait to alloc. Implementation for rust-lang#118959.
2 parents 8c0b4f6 + 180c68b commit 7349ce6

File tree

4 files changed

+535
-43
lines changed

4 files changed

+535
-43
lines changed

library/alloc/src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@
135135
#![feature(iter_next_chunk)]
136136
#![feature(iter_repeat_n)]
137137
#![feature(layout_for_ptr)]
138+
#![feature(local_waker)]
138139
#![feature(maybe_uninit_slice)]
139140
#![feature(maybe_uninit_uninit_array)]
140141
#![feature(maybe_uninit_uninit_array_transpose)]
@@ -252,7 +253,7 @@ pub mod str;
252253
pub mod string;
253254
#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))]
254255
pub mod sync;
255-
#[cfg(all(not(no_global_oom_handling), not(no_rc), not(no_sync), target_has_atomic = "ptr"))]
256+
#[cfg(all(not(no_global_oom_handling), not(no_rc), not(no_sync)))]
256257
pub mod task;
257258
#[cfg(test)]
258259
mod tests;

library/alloc/src/task.rs

+180-5
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,19 @@
22

33
//! Types and Traits for working with asynchronous tasks.
44
//!
5-
//! **Note**: This module is only available on platforms that support atomic
6-
//! loads and stores of pointers. This may be detected at compile time using
5+
//! **Note**: Some of the types in this module are only available
6+
//! on platforms that support atomic loads and stores of pointers.
7+
//! This may be detected at compile time using
78
//! `#[cfg(target_has_atomic = "ptr")]`.
89
10+
use crate::rc::Rc;
911
use core::mem::ManuallyDrop;
10-
use core::task::{RawWaker, RawWakerVTable, Waker};
12+
use core::task::{LocalWaker, RawWaker, RawWakerVTable};
1113

14+
#[cfg(target_has_atomic = "ptr")]
1215
use crate::sync::Arc;
16+
#[cfg(target_has_atomic = "ptr")]
17+
use core::task::Waker;
1318

1419
/// The implementation of waking a task on an executor.
1520
///
@@ -73,6 +78,7 @@ use crate::sync::Arc;
7378
/// println!("Hi from inside a future!");
7479
/// });
7580
/// ```
81+
#[cfg(target_has_atomic = "ptr")]
7682
#[stable(feature = "wake_trait", since = "1.51.0")]
7783
pub trait Wake {
7884
/// Wake this task.
@@ -91,7 +97,7 @@ pub trait Wake {
9197
self.clone().wake();
9298
}
9399
}
94-
100+
#[cfg(target_has_atomic = "ptr")]
95101
#[stable(feature = "wake_trait", since = "1.51.0")]
96102
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
97103
/// Use a `Wake`-able type as a `Waker`.
@@ -103,7 +109,7 @@ impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
103109
unsafe { Waker::from_raw(raw_waker(waker)) }
104110
}
105111
}
106-
112+
#[cfg(target_has_atomic = "ptr")]
107113
#[stable(feature = "wake_trait", since = "1.51.0")]
108114
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
109115
/// Use a `Wake`-able type as a `RawWaker`.
@@ -119,6 +125,7 @@ impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
119125
// the safety of `From<Arc<W>> for Waker` does not depend on the correct
120126
// trait dispatch - instead both impls call this function directly and
121127
// explicitly.
128+
#[cfg(target_has_atomic = "ptr")]
122129
#[inline(always)]
123130
fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
124131
// Increment the reference count of the arc to clone it.
@@ -152,3 +159,171 @@ fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
152159
&RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
153160
)
154161
}
162+
163+
/// An analogous trait to `Wake` but used to construct a `LocalWaker`. This API
164+
/// works in exactly the same way as `Wake`, except that it uses an `Rc` instead
165+
/// of an `Arc`, and the result is a `LocalWaker` instead of a `Waker`.
166+
///
167+
/// The benefits of using `LocalWaker` over `Waker` are that it allows the local waker
168+
/// to hold data that does not implement `Send` and `Sync`. Additionally, it saves calls
169+
/// to `Arc::clone`, which requires atomic synchronization.
170+
///
171+
///
172+
/// # Examples
173+
///
174+
/// This is a simplified example of a `spawn` and a `block_on` function. The `spawn` function
175+
/// is used to push new tasks onto the run queue, while the block on function will remove them
176+
/// and poll them. When a task is woken, it will put itself back on the run queue to be polled
177+
/// by the executor.
178+
///
179+
/// **Note:** This example trades correctness for simplicity. A real world example would interleave
180+
/// poll calls with calls to an io reactor to wait for events instead of spinning on a loop.
181+
///
182+
/// ```rust
183+
/// #![feature(local_waker)]
184+
/// #![feature(noop_waker)]
185+
/// use std::task::{LocalWake, ContextBuilder, LocalWaker, Waker};
186+
/// use std::future::Future;
187+
/// use std::pin::Pin;
188+
/// use std::rc::Rc;
189+
/// use std::cell::RefCell;
190+
/// use std::collections::VecDeque;
191+
///
192+
///
193+
/// thread_local! {
194+
/// // A queue containing all tasks ready to do progress
195+
/// static RUN_QUEUE: RefCell<VecDeque<Rc<Task>>> = RefCell::default();
196+
/// }
197+
///
198+
/// type BoxedFuture = Pin<Box<dyn Future<Output = ()>>>;
199+
///
200+
/// struct Task(RefCell<BoxedFuture>);
201+
///
202+
/// impl LocalWake for Task {
203+
/// fn wake(self: Rc<Self>) {
204+
/// RUN_QUEUE.with_borrow_mut(|queue| {
205+
/// queue.push_back(self)
206+
/// })
207+
/// }
208+
/// }
209+
///
210+
/// fn spawn<F>(future: F)
211+
/// where
212+
/// F: Future<Output=()> + 'static + Send + Sync
213+
/// {
214+
/// let task = RefCell::new(Box::pin(future));
215+
/// RUN_QUEUE.with_borrow_mut(|queue| {
216+
/// queue.push_back(Rc::new(Task(task)));
217+
/// });
218+
/// }
219+
///
220+
/// fn block_on<F>(future: F)
221+
/// where
222+
/// F: Future<Output=()> + 'static + Sync + Send
223+
/// {
224+
/// spawn(future);
225+
/// loop {
226+
/// let Some(task) = RUN_QUEUE.with_borrow_mut(|queue| queue.pop_front()) else {
227+
/// // we exit, since there are no more tasks remaining on the queue
228+
/// return;
229+
/// };
230+
///
231+
/// // cast the Rc<Task> into a `LocalWaker`
232+
/// let local_waker: LocalWaker = task.clone().into();
233+
/// // Build the context using `ContextBuilder`
234+
/// let mut cx = ContextBuilder::from_waker(Waker::noop())
235+
/// .local_waker(&local_waker)
236+
/// .build();
237+
///
238+
/// // Poll the task
239+
/// let _ = task.0
240+
/// .borrow_mut()
241+
/// .as_mut()
242+
/// .poll(&mut cx);
243+
/// }
244+
/// }
245+
///
246+
/// block_on(async {
247+
/// println!("hello world");
248+
/// });
249+
/// ```
250+
///
251+
#[unstable(feature = "local_waker", issue = "118959")]
252+
pub trait LocalWake {
253+
/// Wake this task.
254+
#[unstable(feature = "local_waker", issue = "118959")]
255+
fn wake(self: Rc<Self>);
256+
257+
/// Wake this task without consuming the local waker.
258+
///
259+
/// If an executor supports a cheaper way to wake without consuming the
260+
/// waker, it should override this method. By default, it clones the
261+
/// [`Rc`] and calls [`wake`] on the clone.
262+
///
263+
/// [`wake`]: LocalWaker::wake
264+
#[unstable(feature = "local_waker", issue = "118959")]
265+
fn wake_by_ref(self: &Rc<Self>) {
266+
self.clone().wake();
267+
}
268+
}
269+
270+
#[unstable(feature = "local_waker", issue = "118959")]
271+
impl<W: LocalWake + 'static> From<Rc<W>> for LocalWaker {
272+
/// Use a `Wake`-able type as a `LocalWaker`.
273+
///
274+
/// No heap allocations or atomic operations are used for this conversion.
275+
fn from(waker: Rc<W>) -> LocalWaker {
276+
// SAFETY: This is safe because raw_waker safely constructs
277+
// a RawWaker from Rc<W>.
278+
unsafe { LocalWaker::from_raw(local_raw_waker(waker)) }
279+
}
280+
}
281+
#[allow(ineffective_unstable_trait_impl)]
282+
#[unstable(feature = "local_waker", issue = "118959")]
283+
impl<W: LocalWake + 'static> From<Rc<W>> for RawWaker {
284+
/// Use a `Wake`-able type as a `RawWaker`.
285+
///
286+
/// No heap allocations or atomic operations are used for this conversion.
287+
fn from(waker: Rc<W>) -> RawWaker {
288+
local_raw_waker(waker)
289+
}
290+
}
291+
292+
// NB: This private function for constructing a RawWaker is used, rather than
293+
// inlining this into the `From<Rc<W>> for RawWaker` impl, to ensure that
294+
// the safety of `From<Rc<W>> for Waker` does not depend on the correct
295+
// trait dispatch - instead both impls call this function directly and
296+
// explicitly.
297+
#[inline(always)]
298+
fn local_raw_waker<W: LocalWake + 'static>(waker: Rc<W>) -> RawWaker {
299+
// Increment the reference count of the Rc to clone it.
300+
unsafe fn clone_waker<W: LocalWake + 'static>(waker: *const ()) -> RawWaker {
301+
unsafe { Rc::increment_strong_count(waker as *const W) };
302+
RawWaker::new(
303+
waker as *const (),
304+
&RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
305+
)
306+
}
307+
308+
// Wake by value, moving the Rc into the LocalWake::wake function
309+
unsafe fn wake<W: LocalWake + 'static>(waker: *const ()) {
310+
let waker = unsafe { Rc::from_raw(waker as *const W) };
311+
<W as LocalWake>::wake(waker);
312+
}
313+
314+
// Wake by reference, wrap the waker in ManuallyDrop to avoid dropping it
315+
unsafe fn wake_by_ref<W: LocalWake + 'static>(waker: *const ()) {
316+
let waker = unsafe { ManuallyDrop::new(Rc::from_raw(waker as *const W)) };
317+
<W as LocalWake>::wake_by_ref(&waker);
318+
}
319+
320+
// Decrement the reference count of the Rc on drop
321+
unsafe fn drop_waker<W: LocalWake + 'static>(waker: *const ()) {
322+
unsafe { Rc::decrement_strong_count(waker as *const W) };
323+
}
324+
325+
RawWaker::new(
326+
Rc::into_raw(waker) as *const (),
327+
&RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
328+
)
329+
}

library/core/src/task/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub use self::poll::Poll;
88

99
mod wake;
1010
#[stable(feature = "futures_api", since = "1.36.0")]
11-
pub use self::wake::{Context, RawWaker, RawWakerVTable, Waker};
11+
pub use self::wake::{Context, ContextBuilder, LocalWaker, RawWaker, RawWakerVTable, Waker};
1212

1313
mod ready;
1414
#[stable(feature = "ready_macro", since = "1.64.0")]

0 commit comments

Comments
 (0)