文章目录
标准库代码位于https://github.com/rust-lang/rust/tree/master/library
这里使用目前最新版本1.45.2
涉及的包
std::future::*
对应src/libstd/future.rs
,主要提供以下api
pub use core::future::Future;
pub use core::future::{from_generator, get_context, ResumeTy};
pub use core::future::{pending, ready, Pending, Ready};
pub use core::future::IntoFuture;
core::future
对应src/libcore/future
目录,有以下文件
future.rs
into_future.rs
mod.rs
pending.rs
poll_fn.rs
ready.rs
std::poll::*
和std::wake::*
对应src/libcore/task/mod.rs,主要提供以下api
mod poll;
pub use self::poll::Poll;
mod wake;
pub use self::wake::{Context, RawWaker, RawWakerVTable, Waker};
src/libcore/task目录,有以下文件
mod.rs
poll.rs
wake.rs
Future
src/libcore/future/future.rs
#[lang = "future_trait"]
pub trait Future {
type Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}
Future trait 是异步编程最基础的trait,它有一个poll方法,poll的第二个参数是Context,Context包含一个唤醒函数,poll方法返回Poll::Ready或者Poll::Pending
Context
src/libcore/task/wake.rs
异步任务的上下文,Future的poll方法使用,目前内部只包装了Waker,不排除以后会加其他的东西
pub struct Context<'a> {
waker: &'a Waker,
_marker: PhantomData<fn(&'a ()) -> &'a ()>,
}
impl<'a> Context<'a> {
#[inline]
pub fn from_waker(waker: &'a Waker) -> Self {
Context { waker, _marker: PhantomData }
}
#[inline]
pub fn waker(&self) -> &'a Waker {
&self.waker
}
}
Waker
src/libcore/task/wake.rs
唤醒函数,用于通知executor该task可以运行了,它实现了Send、Sync、Clone,封装了RawWaker实例,RawWaker定义了executor特定的唤醒行为(一般使用条件变量和互斥锁实现wait、notify)
pub struct Waker {
waker: RawWaker,
}
impl Unpin for Waker {}
unsafe impl Send for Waker {}
unsafe impl Sync for Waker {}
impl Clone for Waker {
fn clone(&self) -> Self {
Waker {
waker: unsafe { (self.waker.vtable.clone)(self.waker.data) },
}
}
}
RawWaker
src/libcore/task/wake.rs
#[derive(PartialEq, Debug)]
pub struct RawWaker {
data: *const (),
vtable: &'static RawWakerVTable,
}
RawWakerVTable
src/libcore/task/wake.rs
一个虚拟函数指针表(vtable),用在RawWaker中
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RawWakerVTable {
clone: unsafe fn(*const ()) -> RawWaker,
wake: unsafe fn(*const ()),
wake_by_ref: unsafe fn(*const ()),
drop: unsafe fn(*const ()),
}
Poll
src/libcore/task/poll.rs
Future的poll方法返回值
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Poll<T> {
Ready(T),
Pending,
}
Ready
src/libcore/future/ready.rs
创建一个立即准备好值的Future
#[derive(Debug, Clone)]
pub struct Ready<T>(Option<T>);
impl<T> Unpin for Ready<T> {}
impl<T> Future for Ready<T> {
type Output = T;
#[inline]
fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<T> {
Poll::Ready(self.0.take().expect("Ready polled after completion"))
}
}
pub fn ready<T>(t: T) -> Ready<T> {
Ready(Some(t))
}
eg
#![feature(future_readiness_fns)]
use core::future;
async fn run() {
let a = future::ready(1);
assert_eq!(a.await, 1);
}
Pending
src/libcore/future/pending.rs
创建一个永远也无法完成(计算)的Future
#[derive(Debug)]
pub struct Pending<T> {
_data: marker::PhantomData<T>,
}
pub fn pending<T>() -> Pending<T> {
Pending { _data: marker::PhantomData }
}
impl<T> Future for Pending<T> {
type Output = T;
fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<T> {
Poll::Pending
}
}
eg
#![feature(future_readiness_fns)]
use core::future;
async fn run() {
let future = future::pending();
let () = future.await;
unreachable!();
}
IntoFuture
src/libcore/future/into_future.rs
将一个类型转换成Future
pub trait IntoFuture {
type Output;
type Future: Future<Output = Self::Output>;
fn into_future(self) -> Self::Future;
}
impl<F: Future> IntoFuture for F {
type Output = F::Output;
type Future = F;
fn into_future(self) -> Self::Future {
self
}
}
from_generator
src/libcore/future/mod.rs
- ansyc代码块最终由编译器转换成一个生成器,生成器会包装在GenFuture中,GenFuture实现 Future,在poll中调用生成器的resume方法,如果是状态时Yielded则返回Poll::Pending,如果是Complete(x),则返回Poll::Ready(x)
- ResumeTy 存在的意义:生成器无法实现
for<'a, 'b> Generator<&'a mut Context<'b>>
,因此需要一个裸指针,而裸指针或NonNull无法Send
和Sync
#[derive(Debug, Copy, Clone)]
pub struct ResumeTy(NonNull<Context<'static>>);
unsafe impl Send for ResumeTy {}
unsafe impl Sync for ResumeTy {}
pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
where
T: Generator<ResumeTy, Yield = ()>,
{
struct GenFuture<T: Generator<ResumeTy, Yield = ()>>(T);
impl<T: Generator<ResumeTy, Yield = ()>> !Unpin for GenFuture<T> {}
impl<T: Generator<ResumeTy, Yield = ()>> Future for GenFuture<T> {
type Output = T::Return;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// Safety:!Unpin + !Drop
let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) };
match gen.resume(ResumeTy(NonNull::from(cx).cast::<Context<'static>>())) {
GeneratorState::Yielded(()) => Poll::Pending,
GeneratorState::Complete(x) => Poll::Ready(x),
}
}
}
GenFuture(gen)
}
pub unsafe fn get_context<'a, 'b>(cx: ResumeTy) -> &'a mut Context<'b> {
&mut *cx.0.as_ptr().cast()
}