summaryrefslogtreecommitdiffstats
path: root/tokio/src/executor/task/waker.rs
blob: 11bb135fae436650af4d165b8ea344ea5fff62b0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use crate::executor::task::harness::Harness;
use crate::executor::task::{Header, Schedule};

use std::future::Future;
use std::marker::PhantomData;
use std::ops;
use std::task::{RawWaker, RawWakerVTable, Waker};

pub(super) struct WakerRef<'a, S: 'static> {
    waker: Waker,
    _p: PhantomData<&'a Header<S>>,
}

/// Returns a `WakerRef` which avoids having to pre-emptively increase the
/// refcount if there is no need to do so.
pub(super) fn waker_ref<T, S>(meta: &Header<S>) -> WakerRef<'_, S>
where
    T: Future,
    S: Schedule,
{
    let ptr = meta as *const _ as *const ();

    let vtable = &RawWakerVTable::new(
        clone_waker::<T, S>,
        wake_unreachable,
        wake_by_local_ref::<T, S>,
        noop,
    );

    let waker = unsafe { Waker::from_raw(RawWaker::new(ptr, vtable)) };

    WakerRef {
        waker,
        _p: PhantomData,
    }
}

impl<S> ops::Deref for WakerRef<'_, S> {
    type Target = Waker;

    fn deref(&self) -> &Waker {
        &self.waker
    }
}

unsafe fn clone_waker<T, S>(ptr: *const ()) -> RawWaker
where
    T: Future,
    S: Schedule,
{
    let meta = ptr as *const Header<S>;
    (*meta).state.ref_inc();

    let vtable = &RawWakerVTable::new(
        clone_waker::<T, S>,
        wake_by_val::<T, S>,
        wake_by_ref::<T, S>,
        drop_waker::<T, S>,
    );

    RawWaker::new(ptr, vtable)
}

unsafe fn drop_waker<T, S>(ptr: *const ())
where
    T: Future,
    S: Schedule,
{
    let harness = Harness::<T, S>::from_raw(ptr as *mut _);
    harness.drop_waker();
}

// `wake()` cannot be called on the ref variaant.
unsafe fn wake_unreachable(_data: *const ()) {
    unreachable!();
}

unsafe fn wake_by_val<T, S>(ptr: *const ())
where
    T: Future,
    S: Schedule,
{
    let harness = Harness::<T, S>::from_raw(ptr as *mut _);
    harness.wake_by_val();
}

// This function can only be called when on the runtime.
unsafe fn wake_by_local_ref<T, S>(ptr: *const ())
where
    T: Future,
    S: Schedule,
{
    let harness = Harness::<T, S>::from_raw(ptr as *mut _);
    harness.wake_by_local_ref();
}

// Wake without consuming the waker
unsafe fn wake_by_ref<T, S>(ptr: *const ())
where
    T: Future,
    S: Schedule,
{
    let harness = Harness::<T, S>::from_raw(ptr as *mut _);
    harness.wake_by_ref();
}

unsafe fn noop(_ptr: *const ()) {}