@@ -43,43 +43,46 @@ use std::sync::Arc;
43
43
44
44
/// A trait to be implemented on [super::WakerArray] and [super::WakerVec] for polymorphism.
45
45
/// These are the type that goes in the Arc. They both contain the Readiness and the redirect array/vec.
46
- pub ( super ) trait SharedArcContent {
47
- /// Get the reference of the redirect slice. This is used to compute the index.
46
+ /// # Safety
47
+ /// The `get_redirect_slice` method MUST always return the same slice for the same self.
48
+ pub ( super ) unsafe trait SharedArcContent {
49
+ /// Get the reference of the redirect slice.
48
50
fn get_redirect_slice ( & self ) -> & [ * const Self ] ;
51
+
49
52
/// Called when the subfuture at the specified index should be polled.
50
53
/// Should call `Readiness::set_ready`.
51
54
fn wake_index ( & self , index : usize ) ;
52
55
}
53
56
54
57
/// Create one waker following the mechanism described in the [module][self] doc.
55
- /// The following must be upheld for safety:
56
- /// - `pointer` must points to a slot in the redirect array.
57
- /// - that slot must contain a pointer obtained by `Arc::<A>::into_raw`.
58
- /// - the Arc must still be alive at the time this function is called.
59
- /// The following should be upheld for correct behavior:
60
- /// - calling `SharedArcContent::get_redirect_slice` on the content of the Arc should give the redirect array within which `pointer` points to.
58
+ /// For safety, the index MUST be within bounds of the slice returned by `A::get_redirect_slice()`.
61
59
#[ deny( unsafe_op_in_unsafe_fn) ]
62
60
pub ( super ) unsafe fn waker_from_redirect_position < A : SharedArcContent > (
63
- pointer : * const * const A ,
61
+ arc : Arc < A > ,
62
+ index : usize ,
64
63
) -> Waker {
65
- /// Create a Waker from a type-erased pointer.
66
- /// The pointer must satisfy the safety constraints listed in the wrapping function's documentation.
67
- unsafe fn create_waker < A : SharedArcContent > ( pointer : * const ( ) ) -> RawWaker {
64
+ // For `create_waker`, `wake_by_ref`, `wake`, and `drop_waker`, the following MUST be upheld for safety:
65
+ // - `pointer` must points to a slot in the redirect array.
66
+ // - that slot must contain a pointer of an Arc obtained from `Arc::<A>::into_raw`.
67
+ // - that Arc must still be alive (strong count > 0) at the time the function is called.
68
+
69
+ /// Clone a Waker from a type-erased pointer.
70
+ /// The pointer must satisfy the safety constraints listed in the code comments above.
71
+ unsafe fn clone_waker < A : SharedArcContent > ( pointer : * const ( ) ) -> RawWaker {
68
72
// Retype the type-erased pointer.
69
73
let pointer = pointer as * const * const A ;
70
74
71
- // We're creating a new Waker, so we need to increment the count .
72
- // SAFETY: The constraints listed for the wrapping function documentation means
75
+ // Increment the count so that the Arc won't die before this new Waker we're creating .
76
+ // SAFETY: The required constraints means
73
77
// - `*pointer` is an `*const A` obtained from `Arc::<A>::into_raw`.
74
- // - the Arc is alive.
75
- // So this operation is safe.
78
+ // - the Arc is alive right now.
76
79
unsafe { Arc :: increment_strong_count ( * pointer) } ;
77
80
78
81
RawWaker :: new ( pointer as * const ( ) , create_vtable :: < A > ( ) )
79
82
}
80
83
81
84
/// Invoke `SharedArcContent::wake_index` with the index in the redirect slice where this pointer points to.
82
- /// The pointer must satisfy the safety constraints listed in the wrapping function's documentation .
85
+ /// The pointer must satisfy the safety constraints listed in the code comments above .
83
86
unsafe fn wake_by_ref < A : SharedArcContent > ( pointer : * const ( ) ) {
84
87
// Retype the type-erased pointer.
85
88
let pointer = pointer as * const * const A ;
@@ -89,31 +92,28 @@ pub(super) unsafe fn waker_from_redirect_position<A: SharedArcContent>(
89
92
// SAFETY: we are already requiring the pointer in the redirect array slot to be obtained from `Arc::into_raw`.
90
93
let arc_content: & A = unsafe { & * raw } ;
91
94
92
- // Calculate the index.
93
- // This is your familiar pointer math
94
- // `item_address = array_address + (index * item_size)`
95
- // rearranged to
96
- // `index = (item_address - array_address) / item_size`.
97
- let item_address = sptr:: Strict :: addr ( pointer) ;
98
- let redirect_slice_address = sptr:: Strict :: addr ( arc_content. get_redirect_slice ( ) . as_ptr ( ) ) ;
99
- let redirect_item_size = core:: mem:: size_of :: < * const A > ( ) ; // the size of each item in the redirect slice
100
- let index = ( item_address - redirect_slice_address) / redirect_item_size;
95
+ let slice_start = arc_content. get_redirect_slice ( ) . as_ptr ( ) ;
96
+
97
+ // We'll switch to [`sub_ptr`](https://github.com/rust-lang/rust/issues/95892) once that's stable.
98
+ let index = unsafe { pointer. offset_from ( slice_start) } as usize ;
101
99
102
100
arc_content. wake_index ( index) ;
103
101
}
104
102
105
- /// The pointer must satisfy the safety constraints listed in the wrapping function's documentation.
103
+ /// Drop the waker (and drop the shared Arc if other Wakers and the combinator have all been dropped).
104
+ /// The pointer must satisfy the safety constraints listed in the code comments above.
106
105
unsafe fn drop_waker < A : SharedArcContent > ( pointer : * const ( ) ) {
107
106
// Retype the type-erased pointer.
108
107
let pointer = pointer as * const * const A ;
109
108
110
109
// SAFETY: we are already requiring `pointer` to point to a slot in the redirect array.
111
- let raw = unsafe { * pointer } ;
110
+ let raw: * const A = unsafe { * pointer } ;
112
111
// SAFETY: we are already requiring the pointer in the redirect array slot to be obtained from `Arc::into_raw`.
113
112
unsafe { Arc :: decrement_strong_count ( raw) } ;
114
113
}
115
114
116
- /// The pointer must satisfy the safety constraints listed in the wrapping function's documentation.
115
+ /// Like `wake_by_ref` but consumes the Waker.
116
+ /// The pointer must satisfy the safety constraints listed in the code comments above.
117
117
unsafe fn wake < A : SharedArcContent > ( pointer : * const ( ) ) {
118
118
// SAFETY: we are already requiring the constraints of `wake_by_ref` and `drop_waker`.
119
119
unsafe {
@@ -124,13 +124,27 @@ pub(super) unsafe fn waker_from_redirect_position<A: SharedArcContent>(
124
124
125
125
fn create_vtable < A : SharedArcContent > ( ) -> & ' static RawWakerVTable {
126
126
& RawWakerVTable :: new (
127
- create_waker :: < A > ,
127
+ clone_waker :: < A > ,
128
128
wake :: < A > ,
129
129
wake_by_ref :: < A > ,
130
130
drop_waker :: < A > ,
131
131
)
132
132
}
133
+
134
+ let redirect_slice: & [ * const A ] = arc. get_redirect_slice ( ) ;
135
+
136
+ debug_assert ! ( redirect_slice. len( ) > index) ;
137
+
138
+ // SAFETY: we are already requiring that index be in bound of the slice.
139
+ let pointer: * const * const A = unsafe { redirect_slice. as_ptr ( ) . add ( index) } ;
140
+ // Type-erase the pointer because the Waker methods expect so.
141
+ let pointer = pointer as * const ( ) ;
142
+
143
+ // We want to transfer management of the one strong count associated with `arc` to the Waker we're creating.
144
+ // That count should only be decremented when the Waker is dropped (by `drop_waker`).
145
+ core:: mem:: forget ( arc) ;
146
+
133
147
// SAFETY: All our vtable functions adhere to the RawWakerVTable contract,
134
148
// and we are already requiring that `pointer` is what our functions expect.
135
- unsafe { Waker :: from_raw ( create_waker :: < A > ( pointer as * const ( ) ) ) }
149
+ unsafe { Waker :: from_raw ( RawWaker :: new ( pointer, create_vtable :: < A > ( ) ) ) }
136
150
}
0 commit comments