基本状态转换
核心的数据结构:
核心数据结构是Task,另外还抽象了一个Runnable对象,是对RawTask的封装,实现对RawTask内部方法的调用wrapper,比如schedule、run、waker、 drop_future、drop_ref等
pub struct Task<T, M = ()> {
/// A raw task pointer.
pub(crate) ptr: NonNull<()>,
/// A marker capturing generic types `T` and `M`.
pub(crate) _marker: PhantomData<(T, M)>,
}
// Task的ptr,指向的就是这个RawTask结构
/// Raw pointers to the fields inside a task.
pub(crate) struct RawTask<F, T, S, M> {
/// The task header.
pub(crate) header: *const Header<M>,
/// The schedule function.
pub(crate) schedule: *const S,
/// The future.
pub(crate) future: *mut F,
/// The output of the future.
pub(crate) output: *mut Result<T, Panic>,
}
// 他的ptr指向了在堆上分配的一个Task
pub struct Runnable<M = ()> {
/// A pointer to the heap-allocated task.
pub(crate) ptr: NonNull<()>,
/// A marker capturing generic type `M`.
pub(crate) _marker: PhantomData<M>,
}
Task实现了Future,本质上就是一个Future的修饰器,负责Poll 内部future
impl<T, M> Future for Task<T, M> {
type Output = T;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.poll_task(cx) {
Poll::Ready(t) => Poll::Ready(t.expect("Task polled after completion")),
Poll::Pending => Poll::Pending,
}
}
}
通过spawn来创建Runnable和Task,最终会去调用Builder::spawn_unchecked方法,这个方法内部会构建RawTask,最终创建出Task,其实现如下:
pub fn spawn<F, S>(future: F, schedule: S) -> (Runnable, Task<F::Output>)
where
F: Future + Send + 'static,
F::Output: Send + 'static,
S: Schedule + Send + Sync + 'static,
{
unsafe { spawn_unchecked(future, schedule) }
}
pub unsafe fn spawn_unchecked<F, S>(future: F, schedule: S) -> (Runnable, Task<F::Output>)
where
F: Future,
S: Schedule,
{
Builder::new().spawn_unchecked(move |()| future, schedule)
}
// Builder::spawn_unchecked,给定future和schedule来创建Task
// schedule用来决定Poll Task返回Pending的时候,如果进行调度,把这个Futrue存在哪里
// Builder::spawn_unchecked
pub unsafe fn spawn_unchecked<'a, F, Fut, S>(
self,
future: F,
schedule: S,
) -> (Runnable<M>, Task<Fut::Output, M>)
where
F: FnOnce(&'a M) -> Fut,
Fut: Future + 'a,
S: Schedule<M>,
M: 'a,
{
// Allocate large futures on the heap.
let ptr = if mem::size_of::<Fut>() >= 2048 {
let future = |meta| {
let future = future(meta);
Box::pin(future)
};
RawTask::<_, Fut::Output, S, M>::allocate(future, schedule, self)
} else {
RawTask::<Fut, Fut::Output, S, M>::allocate(future, schedule, self)
};
// 可以看到runnable其实就是指向了分配在队上的RawTask
let runnable = Runnable::from_raw(ptr);
// Task本质上也是对Task的Wrapper,它和runnable的区别,
// 就是Task实现了Future,可以被poll
let task = Task {
ptr,
_marker: PhantomData,
};
(runnable, task)
}
通过上面返回的runnable就可以主动调用schedule来进行调度了,最终会调用到用户通过spawn中指定的Fn(runnable)函数。这里就相当于把RawTask发送给了执行器,交给执行器来Poll Future了。
// Runnable::schedule
pub fn schedule(self) {
// ptr 是RawTask,通过ptr拿到RawTask,然后通过vtable来执行schedule函数
// 这个schedule函数就是用户通过spawn指定的
let ptr = self.ptr.as_ptr();
let header = ptr as *const Header<M>;
mem::forget(self);
// 调用RawTask的vtable中的schedule
unsafe {
((*header).vtable.schedule)(ptr, ScheduleInfo::new(false));
}
}
上面通过Fn(runnable)把RawTask发送给执行器后,执行器会通过调用Runnable::run来运行Task。
// Runnable::schedule
pub fn run(self) -> bool {
let ptr = self.ptr.as_ptr();
let header = ptr as *const Header<M>;
mem::forget(self);
unsafe { ((*header).vtable.run)(ptr) }
}
可以看到Runnable就是一个Wrapper,所有的实现都是通过调用RawTask的vtable来实现的,下面是RawTask定义的一些vtable。