@@ -18,23 +18,29 @@ use super::{Receiver, Sender};
18
18
pub ( crate ) type WaitQueueData = ( Waker , FreeSlotPtr ) ;
19
19
pub ( crate ) type WaitQueue = DoublyLinkedList < WaitQueueData > ;
20
20
21
+ #[ derive( Debug ) ]
22
+ pub ( crate ) struct FreeSlot ( u8 ) ;
23
+
21
24
/// A pointer to a free slot.
22
25
#[ derive( Clone ) ]
23
- pub ( crate ) struct FreeSlotPtr ( * mut Option < u8 > ) ;
26
+ pub ( crate ) struct FreeSlotPtr ( * mut Option < FreeSlot > ) ;
24
27
25
28
impl FreeSlotPtr {
26
29
/// SAFETY: `inner` must be valid until the [`Link`] containing this [`FreeSlotPtr`] is popped.
27
30
/// Additionally, this [`FreeSlotPtr`] must have exclusive access to the data pointed to by
28
31
/// `inner`.
29
- pub unsafe fn new ( inner : * mut Option < u8 > ) -> Self {
32
+ pub unsafe fn new ( inner : * mut Option < FreeSlot > ) -> Self {
30
33
Self ( inner)
31
34
}
32
35
33
36
/// Replace the value of this slot with `new_value`, and return
34
37
/// the old value.
35
38
///
36
39
/// SAFETY: the pointer in this [`FreeSlotPtr`] must be valid for writes.
37
- pub ( crate ) unsafe fn take ( & mut self , cs : critical_section:: CriticalSection ) -> Option < u8 > {
40
+ pub ( crate ) unsafe fn take (
41
+ & mut self ,
42
+ cs : critical_section:: CriticalSection ,
43
+ ) -> Option < FreeSlot > {
38
44
self . replace ( None , cs)
39
45
}
40
46
@@ -45,9 +51,9 @@ impl FreeSlotPtr {
45
51
/// be obtained from `freeq`.
46
52
unsafe fn replace (
47
53
& mut self ,
48
- new_value : Option < u8 > ,
54
+ new_value : Option < FreeSlot > ,
49
55
_cs : critical_section:: CriticalSection ,
50
- ) -> Option < u8 > {
56
+ ) -> Option < FreeSlot > {
51
57
// SAFETY: we are in a critical section.
52
58
unsafe { core:: ptr:: replace ( self . 0 , new_value) }
53
59
}
@@ -147,31 +153,32 @@ impl<T, const N: usize> Channel<T, N> {
147
153
///
148
154
/// This will do one of two things:
149
155
/// 1. If there are any waiting `send`-ers, wake the longest-waiting one and hand it `slot`.
150
- /// 2. else, insert `slot` into `self.freeq` .
156
+ /// 2. else, insert `slot` into the free queue .
151
157
///
152
- /// SAFETY: `slot` must be a `u8` that is obtained from [`Channel::readyq`] or through [`FreeSlotPtr::take`] .
153
- pub ( crate ) unsafe fn push_free_slot ( & self , slot : u8 ) {
158
+ /// SAFETY: `slot` must be obtained from this exact channel instance .
159
+ pub ( crate ) unsafe fn return_free_slot ( & self , slot : FreeSlot ) {
154
160
critical_section:: with ( |cs| {
155
161
fence ( Ordering :: SeqCst ) ;
156
162
157
163
// If a sender is waiting in the `wait_queue`, wake the first one up & hand it the free slot.
158
164
if let Some ( ( wait_head, mut freeq_slot) ) = self . wait_queue . pop ( ) {
159
165
// SAFETY: `freeq_slot` is valid for writes: we are in a critical
160
- // section & the `SlotPtr ` lives for at least the duration of the wait queue link.
166
+ // section & the `FreeSlotPtr ` lives for at least the duration of the wait queue link.
161
167
unsafe { freeq_slot. replace ( Some ( slot) , cs) } ;
162
168
wait_head. wake ( ) ;
163
169
} else {
164
170
assert ! ( !self . access( cs) . freeq. is_full( ) ) ;
165
- unsafe { self . access ( cs) . freeq . push_back_unchecked ( slot) }
171
+ unsafe { self . access ( cs) . freeq . push_back_unchecked ( slot. 0 ) }
166
172
}
167
173
} ) ;
168
174
}
169
175
170
- /// Push a value into a specific slot.
176
+ /// Send a value using the given ` slot` in this channel .
171
177
///
172
- /// SAFETY: `slot` must be obtained from [`Channel::pop_free_slot`] or through a popped [`SlotPtr`] .
178
+ /// SAFETY: `slot` must be obtained from this exact channel instance .
173
179
#[ inline( always) ]
174
- pub ( crate ) unsafe fn slot_ready ( & self , slot : u8 , val : T ) {
180
+ pub ( crate ) unsafe fn send_value ( & self , slot : FreeSlot , val : T ) {
181
+ let slot = slot. 0 ;
175
182
// Write the value to the slots, note; this memcpy is not under a critical section.
176
183
unsafe { ptr:: write ( self . slots . get_unchecked ( slot as usize ) . get ( ) as * mut T , val) }
177
184
@@ -187,16 +194,21 @@ impl<T, const N: usize> Channel<T, N> {
187
194
self . receiver_waker . wake ( ) ;
188
195
}
189
196
190
- /// Pop a ready slot.
191
- pub ( crate ) fn pop_ready_slot ( & self ) -> Option < T > {
197
+ /// Pop the value of a ready slot to make it available to a receiver.
198
+ ///
199
+ /// Internally, this function does these things:
200
+ /// 1. Pop a ready slot from the ready queue.
201
+ /// 2. If available, read the data from the backing slot storage.
202
+ /// 3. If available, return the now-free slot to the free queue.
203
+ pub ( crate ) fn receive_value ( & self ) -> Option < T > {
192
204
let ready_slot = critical_section:: with ( |cs| self . access ( cs) . readyq . pop_front ( ) ) ;
193
205
194
206
if let Some ( rs) = ready_slot {
195
207
let r = unsafe { ptr:: read ( self . slots . get_unchecked ( rs as usize ) . get ( ) as * const T ) } ;
196
208
197
209
// Return the index to the free queue after we've read the value.
198
- // SAFETY: `rs` comes directly from `readyq` .
199
- unsafe { self . push_free_slot ( rs ) } ;
210
+ // SAFETY: `rs` is now a free slot obtained from this channel .
211
+ unsafe { self . return_free_slot ( FreeSlot ( rs ) ) } ;
200
212
201
213
Some ( r)
202
214
} else {
@@ -207,7 +219,7 @@ impl<T, const N: usize> Channel<T, N> {
207
219
/// Register a new waiter in the wait queue.
208
220
///
209
221
/// SAFETY: `link` must be valid until it is popped.
210
- pub ( crate ) unsafe fn push_to_wait_queue ( & self , link : Pin < & Link < WaitQueueData > > ) {
222
+ pub ( crate ) unsafe fn push_wait_queue ( & self , link : Pin < & Link < WaitQueueData > > ) {
211
223
self . wait_queue . push ( link) ;
212
224
}
213
225
@@ -216,8 +228,9 @@ impl<T, const N: usize> Channel<T, N> {
216
228
}
217
229
218
230
/// Pop a free slot.
219
- pub ( crate ) fn pop_free_slot ( & self ) -> Option < u8 > {
220
- critical_section:: with ( |cs| self . access ( cs) . freeq . pop_front ( ) )
231
+ pub ( crate ) fn pop_free_slot ( & self ) -> Option < FreeSlot > {
232
+ let slot = critical_section:: with ( |cs| self . access ( cs) . freeq . pop_front ( ) ) ;
233
+ slot. map ( FreeSlot )
221
234
}
222
235
223
236
pub ( crate ) fn num_senders ( & self ) -> usize {
0 commit comments