sync: add broadcast::Sender::new (#5824)

This commit is contained in:
João Marcos
2023-07-15 18:54:06 +02:00
committed by GitHub
parent 304d140361
commit e52d56e807
+87 -19
View File
@@ -444,9 +444,53 @@ const MAX_RECEIVERS: usize = usize::MAX >> 2;
/// This will panic if `capacity` is equal to `0` or larger /// This will panic if `capacity` is equal to `0` or larger
/// than `usize::MAX / 2`. /// than `usize::MAX / 2`.
#[track_caller] #[track_caller]
pub fn channel<T: Clone>(mut capacity: usize) -> (Sender<T>, Receiver<T>) { pub fn channel<T: Clone>(capacity: usize) -> (Sender<T>, Receiver<T>) {
assert!(capacity > 0, "capacity is empty"); // SAFETY: In the line below we are creating one extra receiver, so there will be 1 in total.
assert!(capacity <= usize::MAX >> 1, "requested capacity too large"); let tx = unsafe { Sender::new_with_receiver_count(1, capacity) };
let rx = Receiver {
shared: tx.shared.clone(),
next: 0,
};
(tx, rx)
}
unsafe impl<T: Send> Send for Sender<T> {}
unsafe impl<T: Send> Sync for Sender<T> {}
unsafe impl<T: Send> Send for Receiver<T> {}
unsafe impl<T: Send> Sync for Receiver<T> {}
impl<T> Sender<T> {
/// Creates the sending-half of the [`broadcast`] channel.
///
/// See documentation of [`broadcast::channel`] for errors when calling this function.
///
/// [`broadcast`]: crate::sync::broadcast
/// [`broadcast::channel`]: crate::sync::broadcast
#[track_caller]
pub fn new(capacity: usize) -> Self {
// SAFETY: We don't create extra receivers, so there are 0.
unsafe { Self::new_with_receiver_count(0, capacity) }
}
/// Creates the sending-half of the [`broadcast`](self) channel, and provide the receiver
/// count.
///
/// See the documentation of [`broadcast::channel`](self::channel) for more errors when
/// calling this function.
///
/// # Safety:
///
/// The caller must ensure that the amount of receivers for this Sender is correct before
/// the channel functionalities are used, the count is zero by default, as this function
/// does not create any receivers by itself.
#[track_caller]
unsafe fn new_with_receiver_count(receiver_count: usize, mut capacity: usize) -> Self {
assert!(capacity > 0, "broadcast channel capacity cannot be zero");
assert!(
capacity <= usize::MAX >> 1,
"broadcast channel capacity exceeded `usize::MAX / 2`"
);
// Round to a power of two // Round to a power of two
capacity = capacity.next_power_of_two(); capacity = capacity.next_power_of_two();
@@ -466,30 +510,16 @@ pub fn channel<T: Clone>(mut capacity: usize) -> (Sender<T>, Receiver<T>) {
mask: capacity - 1, mask: capacity - 1,
tail: Mutex::new(Tail { tail: Mutex::new(Tail {
pos: 0, pos: 0,
rx_cnt: 1, rx_cnt: receiver_count,
closed: false, closed: false,
waiters: LinkedList::new(), waiters: LinkedList::new(),
}), }),
num_tx: AtomicUsize::new(1), num_tx: AtomicUsize::new(1),
}); });
let rx = Receiver { Sender { shared }
shared: shared.clone(),
next: 0,
};
let tx = Sender { shared };
(tx, rx)
} }
unsafe impl<T: Send> Send for Sender<T> {}
unsafe impl<T: Send> Sync for Sender<T> {}
unsafe impl<T: Send> Send for Receiver<T> {}
unsafe impl<T: Send> Sync for Receiver<T> {}
impl<T> Sender<T> {
/// Attempts to send a value to all active [`Receiver`] handles, returning /// Attempts to send a value to all active [`Receiver`] handles, returning
/// it back if it could not be sent. /// it back if it could not be sent.
/// ///
@@ -1370,3 +1400,41 @@ impl<'a, T> Drop for RecvGuard<'a, T> {
} }
fn is_unpin<T: Unpin>() {} fn is_unpin<T: Unpin>() {}
#[cfg(not(loom))]
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn receiver_count_on_sender_constructor() {
let sender = Sender::<i32>::new(16);
assert_eq!(sender.receiver_count(), 0);
let rx_1 = sender.subscribe();
assert_eq!(sender.receiver_count(), 1);
let rx_2 = rx_1.resubscribe();
assert_eq!(sender.receiver_count(), 2);
let rx_3 = sender.subscribe();
assert_eq!(sender.receiver_count(), 3);
drop(rx_3);
drop(rx_1);
assert_eq!(sender.receiver_count(), 1);
drop(rx_2);
assert_eq!(sender.receiver_count(), 0);
}
#[cfg(not(loom))]
#[test]
fn receiver_count_on_channel_constructor() {
let (sender, rx) = channel::<i32>(16);
assert_eq!(sender.receiver_count(), 1);
let _rx_2 = rx.resubscribe();
assert_eq!(sender.receiver_count(), 2);
}
}