基本状态转换

image.png

核心的数据结构:

image.png

核心数据结构是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。