Unclear behaviour of casting ptr of RawTask to ptr of Header
Closed this issue · 1 comments
Hi, I'm going through this repo in order to understand async runtimes better. I'm not able to understand a part of the codebase:
Task
's field ptr
is is a pointer to RawTask
. But in Task
's methods, I see it being casted as a pointer to Header
.
impl Task {
fn poll_task(&mut self, cx: &mut Context<'_>) -> Poll<Option<T>> {
let ptr = self.ptr.as_ptr();
let header = ptr as *const Header<M>;
...
}
...
}
From what I understand, this can happen since ptr to Header
is the first field in RawTask
:
/// Raw pointers to the fields inside a task.
pub(crate) struct RawTask<F, T, S, M> {
/// The task header.
pub(crate) header: *const Header<M>,
...
}
According to this post, shouldn't this be only possible with #[repr(C)]
on RawTask
?
The raw task pointer isn't a pointer to RawTask
, it's a pointer to an anonymous structure whose first field is a Header
.
Specifically, the structure is laid out manually, like so:
Lines 105 to 133 in 918ec72
This roughly translates to this equivalent Rust structure:
#[repr(C)]
struct Anonymous<F, T, S, M> {
header: Header<M>,
result_future_union: union {
future: F,
result: T,
},
schedule: S,
}
This is the structure that the pointer actually points to. Since the header comes first in this structure, we can cast the pointer to the raw task into a Header
pointer without any issues.
The purpose of the RawTask
structure is to provide pointers to the fields of the above anonymous structure. Since we can't actually name the anonymous structure in our code (as it is constructed manually on the heap), we have to refer to its field by pointers. Hence, the pointers to the header, the future, et al. Casting a pointer to RawTask
to a Header
pointer wouldn't actually work, since the header
pointer is a pointer to a Header
, not an actual Header
.