Skip to content

Commit af051a5

Browse files
author
Stjepan Glavina
authored
Add waker and conversion to raw pointer (#16)
1 parent f4ae6f5 commit af051a5

File tree

4 files changed

+88
-2
lines changed

4 files changed

+88
-2
lines changed

Diff for: src/join_handle.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use core::marker::{PhantomData, Unpin};
44
use core::pin::Pin;
55
use core::ptr::NonNull;
66
use core::sync::atomic::Ordering;
7-
use core::task::{Context, Poll};
7+
use core::task::{Context, Poll, Waker};
88

99
use crate::header::Header;
1010
use crate::state::*;
@@ -92,6 +92,17 @@ impl<R, T> JoinHandle<R, T> {
9292
&*raw
9393
}
9494
}
95+
96+
/// Returns a waker associated with the task.
97+
pub fn waker(&self) -> Waker {
98+
let ptr = self.raw_task.as_ptr();
99+
let header = ptr as *const Header;
100+
101+
unsafe {
102+
let raw_waker = ((*header).vtable.clone_waker)(ptr);
103+
Waker::from_raw(raw_waker)
104+
}
105+
}
95106
}
96107

97108
impl<R, T> Drop for JoinHandle<R, T> {

Diff for: src/raw.rs

+4
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ pub(crate) struct TaskVTable {
3535

3636
/// Runs the task.
3737
pub(crate) run: unsafe fn(*const ()),
38+
39+
/// Creates a new waker associated with the task.
40+
pub(crate) clone_waker: unsafe fn(ptr: *const ()) -> RawWaker,
3841
}
3942

4043
/// Memory layout of a task.
@@ -131,6 +134,7 @@ where
131134
drop_task: Self::drop_task,
132135
destroy: Self::destroy,
133136
run: Self::run,
137+
clone_waker: Self::clone_waker,
134138
},
135139
});
136140

Diff for: src/task.rs

+36-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use core::marker::PhantomData;
44
use core::mem::{self, ManuallyDrop};
55
use core::pin::Pin;
66
use core::ptr::NonNull;
7-
use core::task::{Context, Poll};
7+
use core::task::{Context, Poll, Waker};
88

99
use crate::header::Header;
1010
use crate::raw::RawTask;
@@ -264,6 +264,41 @@ impl<T> Task<T> {
264264
&*raw
265265
}
266266
}
267+
268+
/// Converts this task into a raw pointer to the tag.
269+
pub fn into_raw(self) -> *const T {
270+
let offset = Header::offset_tag::<T>();
271+
let ptr = self.raw_task.as_ptr();
272+
mem::forget(self);
273+
274+
unsafe { (ptr as *mut u8).add(offset) as *const T }
275+
}
276+
277+
/// Converts a raw pointer to the tag into a task.
278+
///
279+
/// This method should only be used with raw pointers returned from [`into_raw`].
280+
///
281+
/// [`into_raw`]: #method.into_raw
282+
pub unsafe fn from_raw(raw: *const T) -> Task<T> {
283+
let offset = Header::offset_tag::<T>();
284+
let ptr = (raw as *mut u8).sub(offset) as *mut ();
285+
286+
Task {
287+
raw_task: NonNull::new_unchecked(ptr),
288+
_marker: PhantomData,
289+
}
290+
}
291+
292+
/// Returns a waker associated with this task.
293+
pub fn waker(&self) -> Waker {
294+
let ptr = self.raw_task.as_ptr();
295+
let header = ptr as *const Header;
296+
297+
unsafe {
298+
let raw_waker = ((*header).vtable.clone_waker)(ptr);
299+
Waker::from_raw(raw_waker)
300+
}
301+
}
267302
}
268303

269304
impl<T> Drop for Task<T> {

Diff for: tests/basic.rs

+36
Original file line numberDiff line numberDiff line change
@@ -332,3 +332,39 @@ fn drop_inside_schedule() {
332332
);
333333
task.schedule();
334334
}
335+
336+
#[test]
337+
fn waker() {
338+
let (s, r) = channel::unbounded();
339+
let schedule = move |t| s.send(t).unwrap();
340+
let (task, handle) = async_task::spawn(
341+
future::poll_fn(|_| Poll::<()>::Pending),
342+
schedule,
343+
Box::new(0),
344+
);
345+
346+
assert!(r.is_empty());
347+
let w = task.waker();
348+
task.run();
349+
w.wake();
350+
351+
let task = r.recv().unwrap();
352+
task.run();
353+
handle.waker().wake();
354+
355+
r.recv().unwrap();
356+
}
357+
358+
#[test]
359+
fn raw() {
360+
let (task, _handle) = async_task::spawn(async {}, |_| panic!(), Box::new(AtomicUsize::new(7)));
361+
362+
let a = task.into_raw();
363+
let task = unsafe {
364+
(*a).fetch_add(1, Ordering::SeqCst);
365+
Task::from_raw(a)
366+
};
367+
368+
assert_eq!(task.tag().load(Ordering::SeqCst), 8);
369+
task.run();
370+
}

0 commit comments

Comments
 (0)