How `Waker::wake` in std consume the waker

I do not understand below comments, how waker is consumed by calling (wake)(data)?

    // Don't call `drop` -- the waker will be consumed by `wake`.
    pub fn wake(self) {
        // The actual wakeup call is delegated through a virtual function call
        // to the implementation which is defined by the executor.
        let wake = self.waker.vtable.wake;
        let data = self.waker.data;

        // Don't call `drop` -- the waker will be consumed by `wake`.
        crate::mem::forget(self);

        // SAFETY: This is safe because `Waker::from_raw` is the only way
        // to initialize `wake` and `data` requiring the user to acknowledge
        // that the contract of `RawWaker` is upheld.
        unsafe { (wake)(data) };
    }

Unlike an ordinary Rust move, this is not determined by Rust language rules, but by the specification of the RawWakerVTable:

wake

This function will be called when wake is called on the Waker. It must wake up the task associated with this RawWaker.

The implementation of this function must make sure to release any resources that are associated with this instance of a RawWaker and associated task.

“Must make sure to release any resources” is another way of describing the concept meant by “consumes” — it is what must be done at most once (and preferably exactly once) in all possible code paths. So, the code you quoted calls forget on the Waker to ensure that it doesn't end up calling the vtable's drop() (via impl Drop for Waker) in addition to calling the vtable's wake().

1 Like

@kpreid , thanks, so it leaves the implementor to clean up the resources which is pointed by pointer *const (), right?

The implementor of the waker, who provides the function pointers to the RawWakerVTable, yes.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.