Add `data` to `RawWakerVTable`

Consider add a data (or give it better name) filed to RawWakerVTable structure:

#[stable(feature = "futures_api", since = "1.36.0")]
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RawWakerVTable {
    /// A data pointer, which can be used to store arbitrary data as required
    /// by the executor. This could be e.g. a type-erased pointer to an `Arc`
    /// that is associated with the tasks.
    /// The value of this field gets passed to all functions that are part of
    /// the vtable as the first parameter.
    data: *const (),

    /// 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.
    wake: unsafe fn(*const (), *const ()) -> RawWaker,
    ....
}

This small addition allows treat RawWaker::data as index in some collection of RawWakerVTable::data. Here is an example

struct Helper;

impl Helper {
    fn vtable(queue: Arc<PendingQueue>) -> RawWakerVTable {
       RawWakerVTable::new_with_data(
            queue.as_raw(),
            Self::clone,
            Self::drop,
            Self::wake,
            Self::wake_by_ref,
        )
    }

    fn wake(object: *const (), index: *const ()) {
        let queue: Arc<PendingQueue> = unsafe { mem::transmute(object) };
        queue.push(index as usize);
        queue.wake();
    }

    ...
}

I feel like your motivating example is fairly incomplete, and thus have a hard time understanding the premise/goal of the proposed change here. What are you going to do with the RawWakerVTable created by Helper::vtable?

Usually, RawWakerVTables are interesting for constructing RawWakers.

Given that RawWaker is

pub struct RawWaker {
    data: *const (),
    vtable: &'static RawWakerVTable,
}

I wonder in particular, if and how you plan to create the &'static RawWakerVTable reference for a run-time created vtable such as one created with your Helper::vtable function; or do you also propose to re-design RawWaker, too?

3 Likes

Thanks for your reply, and sorry not being clear. Here the problem I am trying to address: Basically I am asking ability to make a Waker with dynamic VTable. Every time when I am facing with the need to build something like FuturesUnordered I am really miss ability to dynamically crate a Waker which wont refer to some global statics (how i currently solving such kind of problems). Ideally a second data property would be added to RawWaker, one for object and one for offset in that object, but it increasing size of the Waker by one usize, but Waker should be thin as much as possible. And I believe we can extend RawWakerVTable by one usize. And yes you fairly pointed about static reference to RawWakerVTable.

What about storing the dynamic vtable in the value pointed to by the data pointer of the RawWaker and then having a static RawWakerVTable which gets the dynamic vtable from the data?

I faced many times with recommendations to use similar approach, but it has major disadvantage, it requires for each waker to has heap allocated shared pointer pointing to that vtable.

I guess it would have to become something like

pub enum RawWakerVTable {
  V1 {
    wake: unsafe fn(*const ()) -> RawWaker,
    ....
  },
  V2 {
    data: *const (),
    wake: unsafe fn(*const (), *const ()) -> RawWaker,
    ....
  },
}

to be backwards compatible with supporting RawWakerVTable::new. Which would add the discriminant match as a cost to all Waker calls. Or is there an alternative way I'm missing to do this backwards compatibly?

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