@@ -239,15 +239,6 @@ impl<T> Tx<T> {
239239 let _ = unsafe { Box :: from_raw ( block. as_ptr ( ) ) } ;
240240 }
241241 }
242-
243- pub ( crate ) fn is_closed ( & self ) -> bool {
244- let tail = self . block_tail . load ( Acquire ) ;
245-
246- unsafe {
247- let tail_block = & * tail;
248- tail_block. is_closed ( )
249- }
250- }
251242}
252243
253244impl < T > fmt:: Debug for Tx < T > {
@@ -271,11 +262,58 @@ impl<T> Rx<T> {
271262 self . len ( tx) == 0
272263 }
273264
265+ // Guaranteed to return true if `slot_index` is the fake message sent on channel close.
266+ // Guaranteed to return false if `slot_index` is a fully sent message.
267+ //
268+ // For messages that are partially sent, may return either true or false.
269+ fn is_maybe_closed ( & self , tx : & Tx < T > , slot_index : usize ) -> bool {
270+ let start_index = block:: start_index ( slot_index) ;
271+
272+ let tail = tx. block_tail . load ( Acquire ) ;
273+ // SAFETY: Only the receiver frees blocks, so since we are the receiver, this will not be
274+ // freed right now.
275+ let tail_ref = unsafe { & * tail } ;
276+ if tail_ref. is_at_index ( start_index) {
277+ return !tail_ref. has_value ( slot_index) ;
278+ }
279+
280+ // This method is optimized for checking whether the last value is present, so most of the
281+ // time it is in `block_tail`. However, this isn't always the case since it's possible
282+ // that the list was grown with an empty block, in which case `block_tail` points one block
283+ // too far. To handle this case, we walk the list from the head.
284+ let mut block_ptr = Some ( self . head ) ;
285+
286+ while let Some ( block) = block_ptr {
287+ // SAFETY: Only the receiver frees blocks, so since we are the receiver, this will not
288+ // be freed right now.
289+ let block_ref = unsafe { block. as_ref ( ) } ;
290+ if block_ref. is_at_index ( start_index) {
291+ return !block_ref. has_value ( slot_index) ;
292+ }
293+ block_ptr = block_ref. load_next ( Acquire ) ;
294+ }
295+ true
296+ }
297+
274298 pub ( crate ) fn len ( & self , tx : & Tx < T > ) -> usize {
275- // When all the senders are dropped, there will be a last block in the tail position,
276- // but it will be closed
277299 let tail_position = tx. tail_position . load ( Acquire ) ;
278- tail_position - self . index - ( tx. is_closed ( ) as usize )
300+ let mut len = tail_position. wrapping_sub ( self . index ) ;
301+ debug_assert ! ( 0 <= len as isize ) ;
302+ if len == 0 {
303+ return 0 ;
304+ }
305+ // There are messages present in the queue. However, it's possible that the last message is
306+ // a fake "closed" message that we do not wish to count. To avoid counting it, we do not
307+ // count the last message if the ready bit is unset.
308+ //
309+ // Note that it is also possible for the ready bit to be unset on a normal message, but
310+ // this happens only if that message is currently being sent *right now* in parallel on
311+ // another thread. That is okay because it is optional to count messages that are currently
312+ // being sent.
313+ if self . is_maybe_closed ( tx, tail_position. wrapping_sub ( 1 ) ) {
314+ len -= 1 ;
315+ }
316+ len
279317 }
280318
281319 /// Pops the next value off the queue.
0 commit comments