-
Notifications
You must be signed in to change notification settings - Fork 42
Use a single Arc shared between Wakers in WakerArray and WakerVec #118
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
wishawa
wants to merge
5
commits into
yoshuawuyts:main
Choose a base branch
from
wishawa:pr-2-shared-wakers-arc
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 3 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
ca24619
used a single shared Arc between wakers in WakerArray and WakerVec
wishawa b396a85
Use RawWaker to create allocation-free dummy waker
wishawa 1d0be87
add a test for the new Arc-sharing WakerArray
wishawa 4f164de
improve readability, provenance compliance, and documentation for sha…
wishawa 6466c29
simplify creation of WakerArray and WakerVec and make waker_from_redi…
wishawa File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,5 @@ | ||
mod readiness; | ||
mod waker; | ||
mod waker_array; | ||
|
||
pub(crate) use readiness::ReadinessArray; | ||
pub(crate) use waker::InlineWakerArray; | ||
pub(crate) use waker_array::WakerArray; |
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,16 @@ | ||
use std::{sync::Arc, task::Wake}; | ||
use core::task::{RawWaker, RawWakerVTable, Waker}; | ||
|
||
pub(crate) struct DummyWaker(); | ||
impl Wake for DummyWaker { | ||
fn wake(self: Arc<Self>) {} | ||
/// A Waker that doesn't do anything. | ||
pub(crate) fn dummy_waker() -> Waker { | ||
fn new_raw_waker() -> RawWaker { | ||
unsafe fn no_op(_data: *const ()) {} | ||
unsafe fn clone(_data: *const ()) -> RawWaker { | ||
new_raw_waker() | ||
} | ||
RawWaker::new( | ||
core::ptr::null() as *const usize as *const (), | ||
&RawWakerVTable::new(clone, no_op, no_op, no_op), | ||
) | ||
} | ||
unsafe { Waker::from_raw(new_raw_waker()) } | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,12 @@ | ||
mod array; | ||
mod shared_arc; | ||
mod vec; | ||
|
||
#[cfg(test)] | ||
mod dummy; | ||
mod vec; | ||
|
||
#[cfg(test)] | ||
pub(crate) use dummy::DummyWaker; | ||
pub(crate) use dummy::dummy_waker; | ||
|
||
pub(crate) use array::*; | ||
pub(crate) use vec::*; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
use core::task::{RawWaker, RawWakerVTable, Waker}; | ||
use std::sync::Arc; | ||
|
||
// In the diagram below, `A` is the upper block. | ||
wishawa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// It is a struct that implements WakeDataContainer (so either WakerVecInner or WakerArrayInner). | ||
// The lower block is either WakerVec or WakerArray. Each waker there points to a slot of wake_data in `A`. | ||
// Every one of these slots contain a pointer to the Arc wrapping `A` itself. | ||
// Wakers figure out their indices by comparing the address they are pointing to to `wake_data`'s start address. | ||
// | ||
// ┌───────────────────────────┬──────────────┬──────────────┐ | ||
// │ │ │ │ | ||
// │ / ┌─────────────┬──────┼───────┬──────┼───────┬──────┼───────┬─────┐ \ | ||
// ▼ / │ │ │ │ │ │ │ │ │ \ | ||
// Arc < │ Readiness │ wake_data[0] │ wake_data[1] │ wake_data[2] │ ... │ > | ||
// ▲ \ │ │ │ │ │ │ / | ||
// │ \ └─────────────┴──────▲───────┴──────▲───────┴──────▲───────┴─────┘ / | ||
// │ │ │ │ | ||
// └─┐ ┌───────────────┘ │ │ | ||
// │ │ │ │ | ||
// │ │ ┌──────────────────┘ │ | ||
// │ │ │ │ | ||
// │ │ │ ┌─────────────────────┘ | ||
// │ │ │ │ | ||
// │ │ │ │ | ||
// ┌────┼────┬────┼──────┬────┼──────┬────┼──────┬─────┐ | ||
// │ │ │ │ │ │ │ │ │ │ | ||
// │ Inner │ wakers[0] │ wakers[1] │ wakers[2] │ ... │ | ||
// │ │ │ │ │ │ | ||
// └─────────┴───────────┴───────────┴───────────┴─────┘ | ||
|
||
// TODO: Right now each waker gets its own wake_data slot. | ||
// We can save space by making size_of::<usize>() wakers share the same slot. | ||
// With such change, in 64-bit system, the wake_data array/vec would only need ⌈N/8⌉ slots instead of N. | ||
|
||
pub(super) trait WakeDataContainer { | ||
wishawa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// Get the reference of the wake_data slice. This is used to compute the index. | ||
fn get_wake_data_slice(&self) -> &[*const Self]; | ||
/// Called when the subfuture at the specified index should be polled. | ||
fn wake_index(&self, index: usize); | ||
} | ||
pub(super) unsafe fn waker_for_wake_data_slot<A: WakeDataContainer>( | ||
wishawa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
pointer: *const *const A, | ||
) -> Waker { | ||
unsafe fn clone_waker<A: WakeDataContainer>(pointer: *const ()) -> RawWaker { | ||
let pointer = pointer as *const *const A; | ||
let raw = *pointer; // This is the raw pointer of Arc<Inner>. | ||
|
||
// We're creating a new Waker, so we need to increment the count. | ||
Arc::increment_strong_count(raw); | ||
|
||
RawWaker::new(pointer as *const (), create_vtable::<A>()) | ||
} | ||
|
||
// Convert a pointer to a wake_data slot to the Arc<Inner>. | ||
unsafe fn to_arc<A: WakeDataContainer>(pointer: *const *const A) -> Arc<A> { | ||
let raw = *pointer; | ||
Arc::from_raw(raw) | ||
} | ||
unsafe fn wake<A: WakeDataContainer, const BY_REF: bool>(pointer: *const ()) { | ||
let pointer = pointer as *const *const A; | ||
let arc = to_arc::<A>(pointer); | ||
// Calculate the index | ||
let index = ((pointer as usize) // This is the slot our pointer points to. | ||
- (arc.get_wake_data_slice() as *const [*const A] as *const () as usize)) // This is the starting address of wake_data. | ||
/ std::mem::size_of::<*const A>(); | ||
wishawa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
arc.wake_index(index); | ||
|
||
// Dropping the Arc would decrement the strong count. | ||
// We only want to do that when we're not waking by ref. | ||
if BY_REF { | ||
std::mem::forget(arc); | ||
wishawa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} else { | ||
std::mem::drop(arc); | ||
} | ||
} | ||
unsafe fn drop_waker<A: WakeDataContainer>(pointer: *const ()) { | ||
let pointer = pointer as *const *const A; | ||
let arc = to_arc::<A>(pointer); | ||
// Decrement the strong count by dropping the Arc. | ||
std::mem::drop(arc); | ||
wishawa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
fn create_vtable<A: WakeDataContainer>() -> &'static RawWakerVTable { | ||
&RawWakerVTable::new( | ||
clone_waker::<A>, | ||
wake::<A, false>, | ||
wake::<A, true>, | ||
wishawa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
drop_waker::<A>, | ||
) | ||
} | ||
Waker::from_raw(clone_waker::<A>(pointer as *const ())) | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,5 @@ | ||
mod readiness; | ||
mod waker; | ||
mod waker_vec; | ||
|
||
pub(crate) use readiness::ReadinessVec; | ||
pub(crate) use waker::InlineWakerVec; | ||
pub(crate) use waker_vec::WakerVec; |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.