|
10 | 10 |
|
11 | 11 | use std::boxed::Box;
|
12 | 12 | use std::cell::UnsafeCell;
|
13 |
| -use std::mem::{self, MaybeUninit}; |
| 13 | +use std::mem::MaybeUninit; |
14 | 14 | use std::ptr;
|
15 | 15 | use std::sync::atomic::{self, AtomicUsize, Ordering};
|
16 | 16 | use std::time::Instant;
|
@@ -476,21 +476,102 @@ impl<T> Channel<T> {
|
476 | 476 | Some(self.cap())
|
477 | 477 | }
|
478 | 478 |
|
479 |
| - /// Disconnects the channel and wakes up all blocked senders and receivers. |
| 479 | + /// Disconnects senders and wakes up all blocked senders and receivers. |
480 | 480 | ///
|
481 | 481 | /// Returns `true` if this call disconnected the channel.
|
482 |
| - pub(crate) fn disconnect(&self) -> bool { |
| 482 | + pub(crate) fn disconnect_senders(&self) -> bool { |
483 | 483 | let tail = self.tail.fetch_or(self.mark_bit, Ordering::SeqCst);
|
484 | 484 |
|
485 | 485 | if tail & self.mark_bit == 0 {
|
486 |
| - self.senders.disconnect(); |
487 | 486 | self.receivers.disconnect();
|
488 | 487 | true
|
489 | 488 | } else {
|
490 | 489 | false
|
491 | 490 | }
|
492 | 491 | }
|
493 | 492 |
|
| 493 | + /// Disconnects receivers and wakes up all blocked senders. |
| 494 | + /// |
| 495 | + /// Returns `true` if this call disconnected the channel. |
| 496 | + /// |
| 497 | + /// # Safety |
| 498 | + /// May only be called once upon dropping the last receiver. The |
| 499 | + /// destruction of all other receivers must have been observed with acquire |
| 500 | + /// ordering or stronger. |
| 501 | + pub(crate) unsafe fn disconnect_receivers(&self) -> bool { |
| 502 | + let tail = self.tail.fetch_or(self.mark_bit, Ordering::SeqCst); |
| 503 | + let disconnected = if tail & self.mark_bit == 0 { |
| 504 | + self.senders.disconnect(); |
| 505 | + true |
| 506 | + } else { |
| 507 | + false |
| 508 | + }; |
| 509 | + |
| 510 | + unsafe { |
| 511 | + self.discard_all_messages(tail); |
| 512 | + } |
| 513 | + |
| 514 | + disconnected |
| 515 | + } |
| 516 | + |
| 517 | + /// Discards all messages. |
| 518 | + /// |
| 519 | + /// `tail` should be the current (and therefore last) value of `tail`. |
| 520 | + /// |
| 521 | + /// # Panicking |
| 522 | + /// If a destructor panics, the remaining messages are leaked, matching the |
| 523 | + /// behaviour of the unbounded channel. |
| 524 | + /// |
| 525 | + /// # Safety |
| 526 | + /// This method must only be called when dropping the last receiver. The |
| 527 | + /// destruction of all other receivers must have been observed with acquire |
| 528 | + /// ordering or stronger. |
| 529 | + unsafe fn discard_all_messages(&self, tail: usize) { |
| 530 | + debug_assert!(self.is_disconnected()); |
| 531 | + |
| 532 | + // Only receivers modify `head`, so since we are the last one, |
| 533 | + // this value will not change and will not be observed (since |
| 534 | + // no new messages can be sent after disconnection). |
| 535 | + let mut head = self.head.load(Ordering::Relaxed); |
| 536 | + let tail = tail & !self.mark_bit; |
| 537 | + |
| 538 | + let backoff = Backoff::new(); |
| 539 | + loop { |
| 540 | + // Deconstruct the head. |
| 541 | + let index = head & (self.mark_bit - 1); |
| 542 | + let lap = head & !(self.one_lap - 1); |
| 543 | + |
| 544 | + // Inspect the corresponding slot. |
| 545 | + debug_assert!(index < self.buffer.len()); |
| 546 | + let slot = unsafe { self.buffer.get_unchecked(index) }; |
| 547 | + let stamp = slot.stamp.load(Ordering::Acquire); |
| 548 | + |
| 549 | + // If the stamp is ahead of the head by 1, we may drop the message. |
| 550 | + if head + 1 == stamp { |
| 551 | + head = if index + 1 < self.cap() { |
| 552 | + // Same lap, incremented index. |
| 553 | + // Set to `{ lap: lap, mark: 0, index: index + 1 }`. |
| 554 | + head + 1 |
| 555 | + } else { |
| 556 | + // One lap forward, index wraps around to zero. |
| 557 | + // Set to `{ lap: lap.wrapping_add(1), mark: 0, index: 0 }`. |
| 558 | + lap.wrapping_add(self.one_lap) |
| 559 | + }; |
| 560 | + |
| 561 | + unsafe { |
| 562 | + (*slot.msg.get()).assume_init_drop(); |
| 563 | + } |
| 564 | + // If the tail equals the head, that means the channel is empty. |
| 565 | + } else if tail == head { |
| 566 | + return; |
| 567 | + // Otherwise, a sender is about to write into the slot, so we need |
| 568 | + // to wait for it to update the stamp. |
| 569 | + } else { |
| 570 | + backoff.spin(); |
| 571 | + } |
| 572 | + } |
| 573 | + } |
| 574 | + |
494 | 575 | /// Returns `true` if the channel is disconnected.
|
495 | 576 | pub(crate) fn is_disconnected(&self) -> bool {
|
496 | 577 | self.tail.load(Ordering::SeqCst) & self.mark_bit != 0
|
@@ -521,45 +602,6 @@ impl<T> Channel<T> {
|
521 | 602 | }
|
522 | 603 | }
|
523 | 604 |
|
524 |
| -impl<T> Drop for Channel<T> { |
525 |
| - fn drop(&mut self) { |
526 |
| - if mem::needs_drop::<T>() { |
527 |
| - // Get the index of the head. |
528 |
| - let head = *self.head.get_mut(); |
529 |
| - let tail = *self.tail.get_mut(); |
530 |
| - |
531 |
| - let hix = head & (self.mark_bit - 1); |
532 |
| - let tix = tail & (self.mark_bit - 1); |
533 |
| - |
534 |
| - let len = if hix < tix { |
535 |
| - tix - hix |
536 |
| - } else if hix > tix { |
537 |
| - self.cap() - hix + tix |
538 |
| - } else if (tail & !self.mark_bit) == head { |
539 |
| - 0 |
540 |
| - } else { |
541 |
| - self.cap() |
542 |
| - }; |
543 |
| - |
544 |
| - // Loop over all slots that hold a message and drop them. |
545 |
| - for i in 0..len { |
546 |
| - // Compute the index of the next slot holding a message. |
547 |
| - let index = if hix + i < self.cap() { |
548 |
| - hix + i |
549 |
| - } else { |
550 |
| - hix + i - self.cap() |
551 |
| - }; |
552 |
| - |
553 |
| - unsafe { |
554 |
| - debug_assert!(index < self.buffer.len()); |
555 |
| - let slot = self.buffer.get_unchecked_mut(index); |
556 |
| - (*slot.msg.get()).assume_init_drop(); |
557 |
| - } |
558 |
| - } |
559 |
| - } |
560 |
| - } |
561 |
| -} |
562 |
| - |
563 | 605 | /// Receiver handle to a channel.
|
564 | 606 | pub(crate) struct Receiver<'a, T>(&'a Channel<T>);
|
565 | 607 |
|
|
0 commit comments