Repository navigation
Tracking Issue for waker_getters #96992
Copy link
Copy link
Closed
Labels
A-async-awaitArea: Async & AwaitArea: Async & AwaitAsyncAwait-TriagedAsync-await issues that have been triaged during a working group meeting.Async-await issues that have been triaged during a working group meeting.C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCCategory: An issue tracking the progress of sth. like the implementation of an RFCI-async-nominatedNominated for discussion during an async working group meeting.Nominated for discussion during an async working group meeting.T-libs-api[DEPRECATED; DO NOT USE][DEPRECATED; DO NOT USE]WG-asyncWorking group: Async & awaitWorking group: Async & awaitdisposition-mergeThis issue / PR is in PFCP or FCP with a disposition to merge it.This issue / PR is in PFCP or FCP with a disposition to merge it.finished-final-comment-periodThe final comment period is finished for this PR / Issue.The final comment period is finished for this PR / Issue.
Milestone
Description
Feature gate: #![feature(waker_getters)]
This is a tracking issue for getters of data and vtable pointers for RawWaker, and the method to get RawWaker from Waker.
Public API
// core::task
impl RawWaker {
pub fn data(&self) -> *const ();
pub fn vtable(&self) -> &'static RawWakerVTable;
}
impl Waker {
pub fn as_raw(&self) -> &RawWaker;
}Steps / History
- Implementation: Implement
RawWakerandWakergetters for underlying pointers #91828 - Final comment period (FCP)
- Stabilize
waker_getters#129919
Unresolved Questions
- Do we also need
fn into_raw(self) -> RawWakerforWaker? Feature: Provide getters of data and vtable pointer forRawWaker? #87021 (comment)
Reacted by Alex Kocharin
Reacted by José Luis Cruz
Metadata
Metadata
Assignees
Labels
A-async-awaitArea: Async & AwaitArea: Async & AwaitAsyncAwait-TriagedAsync-await issues that have been triaged during a working group meeting.Async-await issues that have been triaged during a working group meeting.C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCCategory: An issue tracking the progress of sth. like the implementation of an RFCI-async-nominatedNominated for discussion during an async working group meeting.Nominated for discussion during an async working group meeting.T-libs-api[DEPRECATED; DO NOT USE][DEPRECATED; DO NOT USE]WG-asyncWorking group: Async & awaitWorking group: Async & awaitdisposition-mergeThis issue / PR is in PFCP or FCP with a disposition to merge it.This issue / PR is in PFCP or FCP with a disposition to merge it.finished-final-comment-periodThe final comment period is finished for this PR / Issue.The final comment period is finished for this PR / Issue.
Activity
oxalica commentedon Sep 8, 2022
Maybe we could stabilize this? Note sure what I could do next. @rust-lang/libs-api
Amanieu commentedon Dec 8, 2022
I am concerned about
as_raw, it's not clear to me how it is intended to be used. It takesWakerby reference and returns aRawWaker, which you can then decompose into a vtable and data pointer. However I don't see how you can then re-construct a reference to the originalWaker: doing so withfrom_rawwill create a secondWakerwhich will call thedropfunction in the vtable when dropped. This can lead to a double-drop once the originalWakeris dropped as well.oxalica commentedon Dec 8, 2022
@Amanieu
It returns
&RawWaker, notRawWaker, thus it's a getter rather than an ownership transfer. Its purpose is to allow getting or checking the underlying data. Reconstructing a[Raw]Wakerfrom the result pointers is indeed incorrect, and unnecessary due to the existence ofWaker::clone.If we do want reconstruction, I'd consider adding another
fn into_raw(Waker) -> RawWaker, which also consists withWaker::from_raw. But I think it's less useful, because we can only access&mut Contextand get a&Waker. We don't own Waker without explicitly cloning it somewhere.Amanieu commentedon Dec 8, 2022
Then I'm afraid that I don't understand how
as_rawis intended to be used. What can you actually do with the returned vtable and data? I can understand passing it through FFI, but then you eventually have to pass it back to Rust code to use it as aWaker.oxalica commentedon Dec 8, 2022
@Amanieu
It's effectively
downcast_refforWaker. It allows validating Waker VTables, ad-hoc optimization, or retrieving data from known Wakers, where the async runtime only supports Wakers from itself. I found an example in,https://github.com/embassy-rs/embassy/blob/be55d2a39eb399d693d11f37dfa4b87cd2bd3c7a/embassy-executor/src/raw/waker.rs#L42
In case of passing through FFI, we need do
&Waker->[*const (); 2]->&Waker1 without ownership transfer. The last step can be done via reconstructingManuallyDrop<Waker>and using the reference to inner. If we want to transfer the ownership via, to sayfn into_raw(Waker) -> RawWaker, we need an extraWaker::cloneduring everypoll.Note that the
ManuallyDrop<Waker>-&Wakerpattern above can be found in,https://github.com/tokio-rs/tokio/blob/c693ccd210c7a318957b0701f4a9632b2d545d6a/tokio/src/util/wake.rs#L18-L22
Footnotes
Since the VTable representation is repr(Rust). Here we actually need to create a new repr(C) VTable for forwarding method calls, rather than to pass the pointer through FFI directly. This is doable currently. ↩
Amanieu commentedon Dec 8, 2022
I feel that a better story is needed for getting a
&Wakerfrom a&RawWaker. Perhaps something like this?Also I do think that we should add
into_rawfor consistency withfrom_raw.oxalica commentedon Dec 10, 2022
This API seems to be the only choice since we cannot let temporary
Wakerinstance escape, but it would be less flexible for thetokiocase. It's not possible to return aimpl Deref<Target = Waker>via this API. For the FFI case, it seems to work though.Also this API is more like a helper, which is able to be implemented outside std (
RawWaker::datacannot, due torepr(Rust)). Should it also be a part ofwaker_getters?Amanieu commentedon Dec 10, 2022
I think it should be inlcuded as the counterpart to
Waker::as_raw, otherwise it isn't clear how theRawWakerreturned byas_rawcan be safely used. This is important for the doc examples for these functions.For tokio, it seems to only be used here. It should be easy to refactor that to use
with_raw.oxalica commentedon Dec 17, 2022
@Amanieu
Noticing that
Wakerisrepr(transparent), it should be safe totransmutefrom&RawWakerto&WakerI think?Then the
with_rawyou suggested can be replaced by,wishawa commentedon Dec 28, 2022
I have a pretty simple use case for this: checking if two Wakers are the same.The Future contract requires wake to be called on the Waker from the latest poll, so on every poll a Future that keeps its Waker stored have to replace its stored Waker with one newly cloned from the Context.Waker::as_rawwould allow us to first compare the two Wakers, avoiding replacement (and the atomic operations involved) if they are the same.Didn't realize
will_wakedoes this already! Thanks @ThomasdezeeuwAmanieu commentedon Dec 29, 2022
Because
Wakerhas private fields, the#[repr(transparent)]is an implementation detail and not an API guarantee that users can rely on. It isn't shown in rustdoc for this reason.The problem with
from_raw_refis that it effectively turns this into a public guarantee: it might be something we can commit to but it would have a higher barrier for acceptance.Thomasdezeeuw commentedon Jan 1, 2023
To add another use case is storing the waker atomically. You can split the data and vtable into two
AtomicU64and store those atomically separately (with some careful programming) or in a singleAtomicU128(on 64 bit archs at least).@wishawa wote that
task::Waker::will_wakeexists for this.conradludgate commentedon Jan 19, 2023
I think it might be natural to think that a
Wakercould do more than justwake(). Like how aBox<dyn Error>might be a specific kind of error with some fields we would care about.I can imagine as situation where you might want to check if the current
Wakeris aFooWakerin order to extract a field from it, eg a TaskID.(I am exploring an idea at the moment to hack in a go like
context.Contexttypemap intocore::task::Contextthrough this mechanism.)In order to do this, I could verify that
waker.raw_waker().vtable() == &FooWakerVTable.(in a similar respect to
Errorandsource, it would be interesting to have awakerchain, especially with the recent push to structured concurrency with many nested sub-executors, but that is for a separate issue and another time)65 remaining items
wyfo commentedon Apr 6, 2024
As I have already mentioned, this feature is not really usable with
alloc::task::Wake.Could it be possible to add the following implementation?
It would allow to match the vtable returned by
RawWaker::vtable.conradludgate commentedon Apr 7, 2024
Does
Waker::from(&arc_wake).as_raw().vtable()not work?wyfo commentedon Apr 7, 2024
Yes it works, but it requires to already have an allocated
arc_wake, which makes the thing unusable.The goal is to compare the vtable of a random waker to know if I can cast its data pointer to my own waker implementation. I don't want to rely for this comparison on a lazily allocated waker to get its vtable (especially as this lazy waker may requires some parameters random to be initialized). In short, this is unusable.
That's too bad, because
Wakeis a convenient implementation shortcut, but I have to rewrite it myself to use this feature.use nightly waker_getters APIs
Hawk777 commentedon Jun 9, 2024
If I understand correctly, the FCP has happened and ended with a disposition to merge. Is there some reason why the FCP checkbox in the first comment is still unticked? In terms of the stabilization PR, is that just waiting for someone to do it, or is there some missing prerequisite?
Amanieu commentedon Jul 8, 2024
This is just waiting for someone to submit a stabilization PR.
kevinmehall commentedon Sep 2, 2024
Submitted a stabilization PR: #129919
Move the `data` and `vtable` methods from `RawWaker` to `Waker`
Add `Waker::new` and `LocalWaker::new`
Rollup merge of rust-lang#129919 - kevinmehall:waker-getters, r=dtolnay
Unrolled build for rust-lang#129919
Rollup merge of #129919 - kevinmehall:waker-getters, r=dtolnay
embassy-executor: update to use stabilized waker_getters