Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
1525
third-party/vendor/crossbeam-channel/src/channel.rs
vendored
Normal file
1525
third-party/vendor/crossbeam-channel/src/channel.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
193
third-party/vendor/crossbeam-channel/src/context.rs
vendored
Normal file
193
third-party/vendor/crossbeam-channel/src/context.rs
vendored
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
//! Thread-local context used in select.
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::ptr;
|
||||
use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::thread::{self, Thread, ThreadId};
|
||||
use std::time::Instant;
|
||||
|
||||
use crossbeam_utils::Backoff;
|
||||
|
||||
use crate::select::Selected;
|
||||
|
||||
/// Thread-local context used in select.
|
||||
// This is a private API that is used by the select macro.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Context {
|
||||
inner: Arc<Inner>,
|
||||
}
|
||||
|
||||
/// Inner representation of `Context`.
|
||||
#[derive(Debug)]
|
||||
struct Inner {
|
||||
/// Selected operation.
|
||||
select: AtomicUsize,
|
||||
|
||||
/// A slot into which another thread may store a pointer to its `Packet`.
|
||||
packet: AtomicPtr<()>,
|
||||
|
||||
/// Thread handle.
|
||||
thread: Thread,
|
||||
|
||||
/// Thread id.
|
||||
thread_id: ThreadId,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
/// Creates a new context for the duration of the closure.
|
||||
#[inline]
|
||||
pub fn with<F, R>(f: F) -> R
|
||||
where
|
||||
F: FnOnce(&Context) -> R,
|
||||
{
|
||||
std::thread_local! {
|
||||
/// Cached thread-local context.
|
||||
static CONTEXT: Cell<Option<Context>> = Cell::new(Some(Context::new()));
|
||||
}
|
||||
|
||||
let mut f = Some(f);
|
||||
let mut f = |cx: &Context| -> R {
|
||||
let f = f.take().unwrap();
|
||||
f(cx)
|
||||
};
|
||||
|
||||
CONTEXT
|
||||
.try_with(|cell| match cell.take() {
|
||||
None => f(&Context::new()),
|
||||
Some(cx) => {
|
||||
cx.reset();
|
||||
let res = f(&cx);
|
||||
cell.set(Some(cx));
|
||||
res
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|_| f(&Context::new()))
|
||||
}
|
||||
|
||||
/// Creates a new `Context`.
|
||||
#[cold]
|
||||
fn new() -> Context {
|
||||
Context {
|
||||
inner: Arc::new(Inner {
|
||||
select: AtomicUsize::new(Selected::Waiting.into()),
|
||||
packet: AtomicPtr::new(ptr::null_mut()),
|
||||
thread: thread::current(),
|
||||
thread_id: thread::current().id(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Resets `select` and `packet`.
|
||||
#[inline]
|
||||
fn reset(&self) {
|
||||
self.inner
|
||||
.select
|
||||
.store(Selected::Waiting.into(), Ordering::Release);
|
||||
self.inner.packet.store(ptr::null_mut(), Ordering::Release);
|
||||
}
|
||||
|
||||
/// Attempts to select an operation.
|
||||
///
|
||||
/// On failure, the previously selected operation is returned.
|
||||
#[inline]
|
||||
pub fn try_select(&self, select: Selected) -> Result<(), Selected> {
|
||||
self.inner
|
||||
.select
|
||||
.compare_exchange(
|
||||
Selected::Waiting.into(),
|
||||
select.into(),
|
||||
Ordering::AcqRel,
|
||||
Ordering::Acquire,
|
||||
)
|
||||
.map(|_| ())
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
/// Returns the selected operation.
|
||||
#[inline]
|
||||
pub fn selected(&self) -> Selected {
|
||||
Selected::from(self.inner.select.load(Ordering::Acquire))
|
||||
}
|
||||
|
||||
/// Stores a packet.
|
||||
///
|
||||
/// This method must be called after `try_select` succeeds and there is a packet to provide.
|
||||
#[inline]
|
||||
pub fn store_packet(&self, packet: *mut ()) {
|
||||
if !packet.is_null() {
|
||||
self.inner.packet.store(packet, Ordering::Release);
|
||||
}
|
||||
}
|
||||
|
||||
/// Waits until a packet is provided and returns it.
|
||||
#[inline]
|
||||
pub fn wait_packet(&self) -> *mut () {
|
||||
let backoff = Backoff::new();
|
||||
loop {
|
||||
let packet = self.inner.packet.load(Ordering::Acquire);
|
||||
if !packet.is_null() {
|
||||
return packet;
|
||||
}
|
||||
backoff.snooze();
|
||||
}
|
||||
}
|
||||
|
||||
/// Waits until an operation is selected and returns it.
|
||||
///
|
||||
/// If the deadline is reached, `Selected::Aborted` will be selected.
|
||||
#[inline]
|
||||
pub fn wait_until(&self, deadline: Option<Instant>) -> Selected {
|
||||
// Spin for a short time, waiting until an operation is selected.
|
||||
let backoff = Backoff::new();
|
||||
loop {
|
||||
let sel = Selected::from(self.inner.select.load(Ordering::Acquire));
|
||||
if sel != Selected::Waiting {
|
||||
return sel;
|
||||
}
|
||||
|
||||
if backoff.is_completed() {
|
||||
break;
|
||||
} else {
|
||||
backoff.snooze();
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
// Check whether an operation has been selected.
|
||||
let sel = Selected::from(self.inner.select.load(Ordering::Acquire));
|
||||
if sel != Selected::Waiting {
|
||||
return sel;
|
||||
}
|
||||
|
||||
// If there's a deadline, park the current thread until the deadline is reached.
|
||||
if let Some(end) = deadline {
|
||||
let now = Instant::now();
|
||||
|
||||
if now < end {
|
||||
thread::park_timeout(end - now);
|
||||
} else {
|
||||
// The deadline has been reached. Try aborting select.
|
||||
return match self.try_select(Selected::Aborted) {
|
||||
Ok(()) => Selected::Aborted,
|
||||
Err(s) => s,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
thread::park();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Unparks the thread this context belongs to.
|
||||
#[inline]
|
||||
pub fn unpark(&self) {
|
||||
self.inner.thread.unpark();
|
||||
}
|
||||
|
||||
/// Returns the id of the thread this context belongs to.
|
||||
#[inline]
|
||||
pub fn thread_id(&self) -> ThreadId {
|
||||
self.inner.thread_id
|
||||
}
|
||||
}
|
||||
145
third-party/vendor/crossbeam-channel/src/counter.rs
vendored
Normal file
145
third-party/vendor/crossbeam-channel/src/counter.rs
vendored
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
//! Reference counter for channels.
|
||||
|
||||
use std::boxed::Box;
|
||||
use std::isize;
|
||||
use std::ops;
|
||||
use std::process;
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
|
||||
/// Reference counter internals.
|
||||
struct Counter<C> {
|
||||
/// The number of senders associated with the channel.
|
||||
senders: AtomicUsize,
|
||||
|
||||
/// The number of receivers associated with the channel.
|
||||
receivers: AtomicUsize,
|
||||
|
||||
/// Set to `true` if the last sender or the last receiver reference deallocates the channel.
|
||||
destroy: AtomicBool,
|
||||
|
||||
/// The internal channel.
|
||||
chan: C,
|
||||
}
|
||||
|
||||
/// Wraps a channel into the reference counter.
|
||||
pub(crate) fn new<C>(chan: C) -> (Sender<C>, Receiver<C>) {
|
||||
let counter = Box::into_raw(Box::new(Counter {
|
||||
senders: AtomicUsize::new(1),
|
||||
receivers: AtomicUsize::new(1),
|
||||
destroy: AtomicBool::new(false),
|
||||
chan,
|
||||
}));
|
||||
let s = Sender { counter };
|
||||
let r = Receiver { counter };
|
||||
(s, r)
|
||||
}
|
||||
|
||||
/// The sending side.
|
||||
pub(crate) struct Sender<C> {
|
||||
counter: *mut Counter<C>,
|
||||
}
|
||||
|
||||
impl<C> Sender<C> {
|
||||
/// Returns the internal `Counter`.
|
||||
fn counter(&self) -> &Counter<C> {
|
||||
unsafe { &*self.counter }
|
||||
}
|
||||
|
||||
/// Acquires another sender reference.
|
||||
pub(crate) fn acquire(&self) -> Sender<C> {
|
||||
let count = self.counter().senders.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
// Cloning senders and calling `mem::forget` on the clones could potentially overflow the
|
||||
// counter. It's very difficult to recover sensibly from such degenerate scenarios so we
|
||||
// just abort when the count becomes very large.
|
||||
if count > isize::MAX as usize {
|
||||
process::abort();
|
||||
}
|
||||
|
||||
Sender {
|
||||
counter: self.counter,
|
||||
}
|
||||
}
|
||||
|
||||
/// Releases the sender reference.
|
||||
///
|
||||
/// Function `disconnect` will be called if this is the last sender reference.
|
||||
pub(crate) unsafe fn release<F: FnOnce(&C) -> bool>(&self, disconnect: F) {
|
||||
if self.counter().senders.fetch_sub(1, Ordering::AcqRel) == 1 {
|
||||
disconnect(&self.counter().chan);
|
||||
|
||||
if self.counter().destroy.swap(true, Ordering::AcqRel) {
|
||||
drop(Box::from_raw(self.counter));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> ops::Deref for Sender<C> {
|
||||
type Target = C;
|
||||
|
||||
fn deref(&self) -> &C {
|
||||
&self.counter().chan
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> PartialEq for Sender<C> {
|
||||
fn eq(&self, other: &Sender<C>) -> bool {
|
||||
self.counter == other.counter
|
||||
}
|
||||
}
|
||||
|
||||
/// The receiving side.
|
||||
pub(crate) struct Receiver<C> {
|
||||
counter: *mut Counter<C>,
|
||||
}
|
||||
|
||||
impl<C> Receiver<C> {
|
||||
/// Returns the internal `Counter`.
|
||||
fn counter(&self) -> &Counter<C> {
|
||||
unsafe { &*self.counter }
|
||||
}
|
||||
|
||||
/// Acquires another receiver reference.
|
||||
pub(crate) fn acquire(&self) -> Receiver<C> {
|
||||
let count = self.counter().receivers.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
// Cloning receivers and calling `mem::forget` on the clones could potentially overflow the
|
||||
// counter. It's very difficult to recover sensibly from such degenerate scenarios so we
|
||||
// just abort when the count becomes very large.
|
||||
if count > isize::MAX as usize {
|
||||
process::abort();
|
||||
}
|
||||
|
||||
Receiver {
|
||||
counter: self.counter,
|
||||
}
|
||||
}
|
||||
|
||||
/// Releases the receiver reference.
|
||||
///
|
||||
/// Function `disconnect` will be called if this is the last receiver reference.
|
||||
pub(crate) unsafe fn release<F: FnOnce(&C) -> bool>(&self, disconnect: F) {
|
||||
if self.counter().receivers.fetch_sub(1, Ordering::AcqRel) == 1 {
|
||||
disconnect(&self.counter().chan);
|
||||
|
||||
if self.counter().destroy.swap(true, Ordering::AcqRel) {
|
||||
drop(Box::from_raw(self.counter));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> ops::Deref for Receiver<C> {
|
||||
type Target = C;
|
||||
|
||||
fn deref(&self) -> &C {
|
||||
&self.counter().chan
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> PartialEq for Receiver<C> {
|
||||
fn eq(&self, other: &Receiver<C>) -> bool {
|
||||
self.counter == other.counter
|
||||
}
|
||||
}
|
||||
378
third-party/vendor/crossbeam-channel/src/err.rs
vendored
Normal file
378
third-party/vendor/crossbeam-channel/src/err.rs
vendored
Normal file
|
|
@ -0,0 +1,378 @@
|
|||
use std::error;
|
||||
use std::fmt;
|
||||
|
||||
/// An error returned from the [`send`] method.
|
||||
///
|
||||
/// The message could not be sent because the channel is disconnected.
|
||||
///
|
||||
/// The error contains the message so it can be recovered.
|
||||
///
|
||||
/// [`send`]: super::Sender::send
|
||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||
pub struct SendError<T>(pub T);
|
||||
|
||||
/// An error returned from the [`try_send`] method.
|
||||
///
|
||||
/// The error contains the message being sent so it can be recovered.
|
||||
///
|
||||
/// [`try_send`]: super::Sender::try_send
|
||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||
pub enum TrySendError<T> {
|
||||
/// The message could not be sent because the channel is full.
|
||||
///
|
||||
/// If this is a zero-capacity channel, then the error indicates that there was no receiver
|
||||
/// available to receive the message at the time.
|
||||
Full(T),
|
||||
|
||||
/// The message could not be sent because the channel is disconnected.
|
||||
Disconnected(T),
|
||||
}
|
||||
|
||||
/// An error returned from the [`send_timeout`] method.
|
||||
///
|
||||
/// The error contains the message being sent so it can be recovered.
|
||||
///
|
||||
/// [`send_timeout`]: super::Sender::send_timeout
|
||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||
pub enum SendTimeoutError<T> {
|
||||
/// The message could not be sent because the channel is full and the operation timed out.
|
||||
///
|
||||
/// If this is a zero-capacity channel, then the error indicates that there was no receiver
|
||||
/// available to receive the message and the operation timed out.
|
||||
Timeout(T),
|
||||
|
||||
/// The message could not be sent because the channel is disconnected.
|
||||
Disconnected(T),
|
||||
}
|
||||
|
||||
/// An error returned from the [`recv`] method.
|
||||
///
|
||||
/// A message could not be received because the channel is empty and disconnected.
|
||||
///
|
||||
/// [`recv`]: super::Receiver::recv
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub struct RecvError;
|
||||
|
||||
/// An error returned from the [`try_recv`] method.
|
||||
///
|
||||
/// [`try_recv`]: super::Receiver::try_recv
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum TryRecvError {
|
||||
/// A message could not be received because the channel is empty.
|
||||
///
|
||||
/// If this is a zero-capacity channel, then the error indicates that there was no sender
|
||||
/// available to send a message at the time.
|
||||
Empty,
|
||||
|
||||
/// The message could not be received because the channel is empty and disconnected.
|
||||
Disconnected,
|
||||
}
|
||||
|
||||
/// An error returned from the [`recv_timeout`] method.
|
||||
///
|
||||
/// [`recv_timeout`]: super::Receiver::recv_timeout
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum RecvTimeoutError {
|
||||
/// A message could not be received because the channel is empty and the operation timed out.
|
||||
///
|
||||
/// If this is a zero-capacity channel, then the error indicates that there was no sender
|
||||
/// available to send a message and the operation timed out.
|
||||
Timeout,
|
||||
|
||||
/// The message could not be received because the channel is empty and disconnected.
|
||||
Disconnected,
|
||||
}
|
||||
|
||||
/// An error returned from the [`try_select`] method.
|
||||
///
|
||||
/// Failed because none of the channel operations were ready.
|
||||
///
|
||||
/// [`try_select`]: super::Select::try_select
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub struct TrySelectError;
|
||||
|
||||
/// An error returned from the [`select_timeout`] method.
|
||||
///
|
||||
/// Failed because none of the channel operations became ready before the timeout.
|
||||
///
|
||||
/// [`select_timeout`]: super::Select::select_timeout
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub struct SelectTimeoutError;
|
||||
|
||||
/// An error returned from the [`try_ready`] method.
|
||||
///
|
||||
/// Failed because none of the channel operations were ready.
|
||||
///
|
||||
/// [`try_ready`]: super::Select::try_ready
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub struct TryReadyError;
|
||||
|
||||
/// An error returned from the [`ready_timeout`] method.
|
||||
///
|
||||
/// Failed because none of the channel operations became ready before the timeout.
|
||||
///
|
||||
/// [`ready_timeout`]: super::Select::ready_timeout
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub struct ReadyTimeoutError;
|
||||
|
||||
impl<T> fmt::Debug for SendError<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
"SendError(..)".fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Display for SendError<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
"sending on a disconnected channel".fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send> error::Error for SendError<T> {}
|
||||
|
||||
impl<T> SendError<T> {
|
||||
/// Unwraps the message.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use crossbeam_channel::unbounded;
|
||||
///
|
||||
/// let (s, r) = unbounded();
|
||||
/// drop(r);
|
||||
///
|
||||
/// if let Err(err) = s.send("foo") {
|
||||
/// assert_eq!(err.into_inner(), "foo");
|
||||
/// }
|
||||
/// ```
|
||||
pub fn into_inner(self) -> T {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for TrySendError<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
TrySendError::Full(..) => "Full(..)".fmt(f),
|
||||
TrySendError::Disconnected(..) => "Disconnected(..)".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Display for TrySendError<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
TrySendError::Full(..) => "sending on a full channel".fmt(f),
|
||||
TrySendError::Disconnected(..) => "sending on a disconnected channel".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send> error::Error for TrySendError<T> {}
|
||||
|
||||
impl<T> From<SendError<T>> for TrySendError<T> {
|
||||
fn from(err: SendError<T>) -> TrySendError<T> {
|
||||
match err {
|
||||
SendError(t) => TrySendError::Disconnected(t),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TrySendError<T> {
|
||||
/// Unwraps the message.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use crossbeam_channel::bounded;
|
||||
///
|
||||
/// let (s, r) = bounded(0);
|
||||
///
|
||||
/// if let Err(err) = s.try_send("foo") {
|
||||
/// assert_eq!(err.into_inner(), "foo");
|
||||
/// }
|
||||
/// ```
|
||||
pub fn into_inner(self) -> T {
|
||||
match self {
|
||||
TrySendError::Full(v) => v,
|
||||
TrySendError::Disconnected(v) => v,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the send operation failed because the channel is full.
|
||||
pub fn is_full(&self) -> bool {
|
||||
match self {
|
||||
TrySendError::Full(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the send operation failed because the channel is disconnected.
|
||||
pub fn is_disconnected(&self) -> bool {
|
||||
match self {
|
||||
TrySendError::Disconnected(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for SendTimeoutError<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
"SendTimeoutError(..)".fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Display for SendTimeoutError<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
SendTimeoutError::Timeout(..) => "timed out waiting on send operation".fmt(f),
|
||||
SendTimeoutError::Disconnected(..) => "sending on a disconnected channel".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send> error::Error for SendTimeoutError<T> {}
|
||||
|
||||
impl<T> From<SendError<T>> for SendTimeoutError<T> {
|
||||
fn from(err: SendError<T>) -> SendTimeoutError<T> {
|
||||
match err {
|
||||
SendError(e) => SendTimeoutError::Disconnected(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SendTimeoutError<T> {
|
||||
/// Unwraps the message.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::time::Duration;
|
||||
/// use crossbeam_channel::unbounded;
|
||||
///
|
||||
/// let (s, r) = unbounded();
|
||||
///
|
||||
/// if let Err(err) = s.send_timeout("foo", Duration::from_secs(1)) {
|
||||
/// assert_eq!(err.into_inner(), "foo");
|
||||
/// }
|
||||
/// ```
|
||||
pub fn into_inner(self) -> T {
|
||||
match self {
|
||||
SendTimeoutError::Timeout(v) => v,
|
||||
SendTimeoutError::Disconnected(v) => v,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the send operation timed out.
|
||||
pub fn is_timeout(&self) -> bool {
|
||||
match self {
|
||||
SendTimeoutError::Timeout(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the send operation failed because the channel is disconnected.
|
||||
pub fn is_disconnected(&self) -> bool {
|
||||
match self {
|
||||
SendTimeoutError::Disconnected(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for RecvError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
"receiving on an empty and disconnected channel".fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for RecvError {}
|
||||
|
||||
impl fmt::Display for TryRecvError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
TryRecvError::Empty => "receiving on an empty channel".fmt(f),
|
||||
TryRecvError::Disconnected => "receiving on an empty and disconnected channel".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for TryRecvError {}
|
||||
|
||||
impl From<RecvError> for TryRecvError {
|
||||
fn from(err: RecvError) -> TryRecvError {
|
||||
match err {
|
||||
RecvError => TryRecvError::Disconnected,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryRecvError {
|
||||
/// Returns `true` if the receive operation failed because the channel is empty.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
match self {
|
||||
TryRecvError::Empty => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the receive operation failed because the channel is disconnected.
|
||||
pub fn is_disconnected(&self) -> bool {
|
||||
match self {
|
||||
TryRecvError::Disconnected => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for RecvTimeoutError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
RecvTimeoutError::Timeout => "timed out waiting on receive operation".fmt(f),
|
||||
RecvTimeoutError::Disconnected => "channel is empty and disconnected".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for RecvTimeoutError {}
|
||||
|
||||
impl From<RecvError> for RecvTimeoutError {
|
||||
fn from(err: RecvError) -> RecvTimeoutError {
|
||||
match err {
|
||||
RecvError => RecvTimeoutError::Disconnected,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RecvTimeoutError {
|
||||
/// Returns `true` if the receive operation timed out.
|
||||
pub fn is_timeout(&self) -> bool {
|
||||
match self {
|
||||
RecvTimeoutError::Timeout => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the receive operation failed because the channel is disconnected.
|
||||
pub fn is_disconnected(&self) -> bool {
|
||||
match self {
|
||||
RecvTimeoutError::Disconnected => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for TrySelectError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
"all operations in select would block".fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for TrySelectError {}
|
||||
|
||||
impl fmt::Display for SelectTimeoutError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
"timed out waiting on select".fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for SelectTimeoutError {}
|
||||
637
third-party/vendor/crossbeam-channel/src/flavors/array.rs
vendored
Normal file
637
third-party/vendor/crossbeam-channel/src/flavors/array.rs
vendored
Normal file
|
|
@ -0,0 +1,637 @@
|
|||
//! Bounded channel based on a preallocated array.
|
||||
//!
|
||||
//! This flavor has a fixed, positive capacity.
|
||||
//!
|
||||
//! The implementation is based on Dmitry Vyukov's bounded MPMC queue.
|
||||
//!
|
||||
//! Source:
|
||||
//! - <http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue>
|
||||
//! - <https://docs.google.com/document/d/1yIAYmbvL3JxOKOjuCyon7JhW4cSv1wy5hC0ApeGMV9s/pub>
|
||||
|
||||
use std::boxed::Box;
|
||||
use std::cell::UnsafeCell;
|
||||
use std::mem::{self, MaybeUninit};
|
||||
use std::ptr;
|
||||
use std::sync::atomic::{self, AtomicUsize, Ordering};
|
||||
use std::time::Instant;
|
||||
|
||||
use crossbeam_utils::{Backoff, CachePadded};
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::err::{RecvTimeoutError, SendTimeoutError, TryRecvError, TrySendError};
|
||||
use crate::select::{Operation, SelectHandle, Selected, Token};
|
||||
use crate::waker::SyncWaker;
|
||||
|
||||
/// A slot in a channel.
|
||||
struct Slot<T> {
|
||||
/// The current stamp.
|
||||
stamp: AtomicUsize,
|
||||
|
||||
/// The message in this slot.
|
||||
msg: UnsafeCell<MaybeUninit<T>>,
|
||||
}
|
||||
|
||||
/// The token type for the array flavor.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ArrayToken {
|
||||
/// Slot to read from or write to.
|
||||
slot: *const u8,
|
||||
|
||||
/// Stamp to store into the slot after reading or writing.
|
||||
stamp: usize,
|
||||
}
|
||||
|
||||
impl Default for ArrayToken {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
ArrayToken {
|
||||
slot: ptr::null(),
|
||||
stamp: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Bounded channel based on a preallocated array.
|
||||
pub(crate) struct Channel<T> {
|
||||
/// The head of the channel.
|
||||
///
|
||||
/// This value is a "stamp" consisting of an index into the buffer, a mark bit, and a lap, but
|
||||
/// packed into a single `usize`. The lower bits represent the index, while the upper bits
|
||||
/// represent the lap. The mark bit in the head is always zero.
|
||||
///
|
||||
/// Messages are popped from the head of the channel.
|
||||
head: CachePadded<AtomicUsize>,
|
||||
|
||||
/// The tail of the channel.
|
||||
///
|
||||
/// This value is a "stamp" consisting of an index into the buffer, a mark bit, and a lap, but
|
||||
/// packed into a single `usize`. The lower bits represent the index, while the upper bits
|
||||
/// represent the lap. The mark bit indicates that the channel is disconnected.
|
||||
///
|
||||
/// Messages are pushed into the tail of the channel.
|
||||
tail: CachePadded<AtomicUsize>,
|
||||
|
||||
/// The buffer holding slots.
|
||||
buffer: Box<[Slot<T>]>,
|
||||
|
||||
/// The channel capacity.
|
||||
cap: usize,
|
||||
|
||||
/// A stamp with the value of `{ lap: 1, mark: 0, index: 0 }`.
|
||||
one_lap: usize,
|
||||
|
||||
/// If this bit is set in the tail, that means the channel is disconnected.
|
||||
mark_bit: usize,
|
||||
|
||||
/// Senders waiting while the channel is full.
|
||||
senders: SyncWaker,
|
||||
|
||||
/// Receivers waiting while the channel is empty and not disconnected.
|
||||
receivers: SyncWaker,
|
||||
}
|
||||
|
||||
impl<T> Channel<T> {
|
||||
/// Creates a bounded channel of capacity `cap`.
|
||||
pub(crate) fn with_capacity(cap: usize) -> Self {
|
||||
assert!(cap > 0, "capacity must be positive");
|
||||
|
||||
// Compute constants `mark_bit` and `one_lap`.
|
||||
let mark_bit = (cap + 1).next_power_of_two();
|
||||
let one_lap = mark_bit * 2;
|
||||
|
||||
// Head is initialized to `{ lap: 0, mark: 0, index: 0 }`.
|
||||
let head = 0;
|
||||
// Tail is initialized to `{ lap: 0, mark: 0, index: 0 }`.
|
||||
let tail = 0;
|
||||
|
||||
// Allocate a buffer of `cap` slots initialized
|
||||
// with stamps.
|
||||
let buffer: Box<[Slot<T>]> = (0..cap)
|
||||
.map(|i| {
|
||||
// Set the stamp to `{ lap: 0, mark: 0, index: i }`.
|
||||
Slot {
|
||||
stamp: AtomicUsize::new(i),
|
||||
msg: UnsafeCell::new(MaybeUninit::uninit()),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
Channel {
|
||||
buffer,
|
||||
cap,
|
||||
one_lap,
|
||||
mark_bit,
|
||||
head: CachePadded::new(AtomicUsize::new(head)),
|
||||
tail: CachePadded::new(AtomicUsize::new(tail)),
|
||||
senders: SyncWaker::new(),
|
||||
receivers: SyncWaker::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a receiver handle to the channel.
|
||||
pub(crate) fn receiver(&self) -> Receiver<'_, T> {
|
||||
Receiver(self)
|
||||
}
|
||||
|
||||
/// Returns a sender handle to the channel.
|
||||
pub(crate) fn sender(&self) -> Sender<'_, T> {
|
||||
Sender(self)
|
||||
}
|
||||
|
||||
/// Attempts to reserve a slot for sending a message.
|
||||
fn start_send(&self, token: &mut Token) -> bool {
|
||||
let backoff = Backoff::new();
|
||||
let mut tail = self.tail.load(Ordering::Relaxed);
|
||||
|
||||
loop {
|
||||
// Check if the channel is disconnected.
|
||||
if tail & self.mark_bit != 0 {
|
||||
token.array.slot = ptr::null();
|
||||
token.array.stamp = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Deconstruct the tail.
|
||||
let index = tail & (self.mark_bit - 1);
|
||||
let lap = tail & !(self.one_lap - 1);
|
||||
|
||||
// Inspect the corresponding slot.
|
||||
debug_assert!(index < self.buffer.len());
|
||||
let slot = unsafe { self.buffer.get_unchecked(index) };
|
||||
let stamp = slot.stamp.load(Ordering::Acquire);
|
||||
|
||||
// If the tail and the stamp match, we may attempt to push.
|
||||
if tail == stamp {
|
||||
let new_tail = if index + 1 < self.cap {
|
||||
// Same lap, incremented index.
|
||||
// Set to `{ lap: lap, mark: 0, index: index + 1 }`.
|
||||
tail + 1
|
||||
} else {
|
||||
// One lap forward, index wraps around to zero.
|
||||
// Set to `{ lap: lap.wrapping_add(1), mark: 0, index: 0 }`.
|
||||
lap.wrapping_add(self.one_lap)
|
||||
};
|
||||
|
||||
// Try moving the tail.
|
||||
match self.tail.compare_exchange_weak(
|
||||
tail,
|
||||
new_tail,
|
||||
Ordering::SeqCst,
|
||||
Ordering::Relaxed,
|
||||
) {
|
||||
Ok(_) => {
|
||||
// Prepare the token for the follow-up call to `write`.
|
||||
token.array.slot = slot as *const Slot<T> as *const u8;
|
||||
token.array.stamp = tail + 1;
|
||||
return true;
|
||||
}
|
||||
Err(t) => {
|
||||
tail = t;
|
||||
backoff.spin();
|
||||
}
|
||||
}
|
||||
} else if stamp.wrapping_add(self.one_lap) == tail + 1 {
|
||||
atomic::fence(Ordering::SeqCst);
|
||||
let head = self.head.load(Ordering::Relaxed);
|
||||
|
||||
// If the head lags one lap behind the tail as well...
|
||||
if head.wrapping_add(self.one_lap) == tail {
|
||||
// ...then the channel is full.
|
||||
return false;
|
||||
}
|
||||
|
||||
backoff.spin();
|
||||
tail = self.tail.load(Ordering::Relaxed);
|
||||
} else {
|
||||
// Snooze because we need to wait for the stamp to get updated.
|
||||
backoff.snooze();
|
||||
tail = self.tail.load(Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a message into the channel.
|
||||
pub(crate) unsafe fn write(&self, token: &mut Token, msg: T) -> Result<(), T> {
|
||||
// If there is no slot, the channel is disconnected.
|
||||
if token.array.slot.is_null() {
|
||||
return Err(msg);
|
||||
}
|
||||
|
||||
let slot: &Slot<T> = &*token.array.slot.cast::<Slot<T>>();
|
||||
|
||||
// Write the message into the slot and update the stamp.
|
||||
slot.msg.get().write(MaybeUninit::new(msg));
|
||||
slot.stamp.store(token.array.stamp, Ordering::Release);
|
||||
|
||||
// Wake a sleeping receiver.
|
||||
self.receivers.notify();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Attempts to reserve a slot for receiving a message.
|
||||
fn start_recv(&self, token: &mut Token) -> bool {
|
||||
let backoff = Backoff::new();
|
||||
let mut head = self.head.load(Ordering::Relaxed);
|
||||
|
||||
loop {
|
||||
// Deconstruct the head.
|
||||
let index = head & (self.mark_bit - 1);
|
||||
let lap = head & !(self.one_lap - 1);
|
||||
|
||||
// Inspect the corresponding slot.
|
||||
debug_assert!(index < self.buffer.len());
|
||||
let slot = unsafe { self.buffer.get_unchecked(index) };
|
||||
let stamp = slot.stamp.load(Ordering::Acquire);
|
||||
|
||||
// If the the stamp is ahead of the head by 1, we may attempt to pop.
|
||||
if head + 1 == stamp {
|
||||
let new = if index + 1 < self.cap {
|
||||
// Same lap, incremented index.
|
||||
// Set to `{ lap: lap, mark: 0, index: index + 1 }`.
|
||||
head + 1
|
||||
} else {
|
||||
// One lap forward, index wraps around to zero.
|
||||
// Set to `{ lap: lap.wrapping_add(1), mark: 0, index: 0 }`.
|
||||
lap.wrapping_add(self.one_lap)
|
||||
};
|
||||
|
||||
// Try moving the head.
|
||||
match self.head.compare_exchange_weak(
|
||||
head,
|
||||
new,
|
||||
Ordering::SeqCst,
|
||||
Ordering::Relaxed,
|
||||
) {
|
||||
Ok(_) => {
|
||||
// Prepare the token for the follow-up call to `read`.
|
||||
token.array.slot = slot as *const Slot<T> as *const u8;
|
||||
token.array.stamp = head.wrapping_add(self.one_lap);
|
||||
return true;
|
||||
}
|
||||
Err(h) => {
|
||||
head = h;
|
||||
backoff.spin();
|
||||
}
|
||||
}
|
||||
} else if stamp == head {
|
||||
atomic::fence(Ordering::SeqCst);
|
||||
let tail = self.tail.load(Ordering::Relaxed);
|
||||
|
||||
// If the tail equals the head, that means the channel is empty.
|
||||
if (tail & !self.mark_bit) == head {
|
||||
// If the channel is disconnected...
|
||||
if tail & self.mark_bit != 0 {
|
||||
// ...then receive an error.
|
||||
token.array.slot = ptr::null();
|
||||
token.array.stamp = 0;
|
||||
return true;
|
||||
} else {
|
||||
// Otherwise, the receive operation is not ready.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
backoff.spin();
|
||||
head = self.head.load(Ordering::Relaxed);
|
||||
} else {
|
||||
// Snooze because we need to wait for the stamp to get updated.
|
||||
backoff.snooze();
|
||||
head = self.head.load(Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads a message from the channel.
|
||||
pub(crate) unsafe fn read(&self, token: &mut Token) -> Result<T, ()> {
|
||||
if token.array.slot.is_null() {
|
||||
// The channel is disconnected.
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let slot: &Slot<T> = &*token.array.slot.cast::<Slot<T>>();
|
||||
|
||||
// Read the message from the slot and update the stamp.
|
||||
let msg = slot.msg.get().read().assume_init();
|
||||
slot.stamp.store(token.array.stamp, Ordering::Release);
|
||||
|
||||
// Wake a sleeping sender.
|
||||
self.senders.notify();
|
||||
Ok(msg)
|
||||
}
|
||||
|
||||
/// Attempts to send a message into the channel.
|
||||
pub(crate) fn try_send(&self, msg: T) -> Result<(), TrySendError<T>> {
|
||||
let token = &mut Token::default();
|
||||
if self.start_send(token) {
|
||||
unsafe { self.write(token, msg).map_err(TrySendError::Disconnected) }
|
||||
} else {
|
||||
Err(TrySendError::Full(msg))
|
||||
}
|
||||
}
|
||||
|
||||
/// Sends a message into the channel.
|
||||
pub(crate) fn send(
|
||||
&self,
|
||||
msg: T,
|
||||
deadline: Option<Instant>,
|
||||
) -> Result<(), SendTimeoutError<T>> {
|
||||
let token = &mut Token::default();
|
||||
loop {
|
||||
// Try sending a message several times.
|
||||
let backoff = Backoff::new();
|
||||
loop {
|
||||
if self.start_send(token) {
|
||||
let res = unsafe { self.write(token, msg) };
|
||||
return res.map_err(SendTimeoutError::Disconnected);
|
||||
}
|
||||
|
||||
if backoff.is_completed() {
|
||||
break;
|
||||
} else {
|
||||
backoff.snooze();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(d) = deadline {
|
||||
if Instant::now() >= d {
|
||||
return Err(SendTimeoutError::Timeout(msg));
|
||||
}
|
||||
}
|
||||
|
||||
Context::with(|cx| {
|
||||
// Prepare for blocking until a receiver wakes us up.
|
||||
let oper = Operation::hook(token);
|
||||
self.senders.register(oper, cx);
|
||||
|
||||
// Has the channel become ready just now?
|
||||
if !self.is_full() || self.is_disconnected() {
|
||||
let _ = cx.try_select(Selected::Aborted);
|
||||
}
|
||||
|
||||
// Block the current thread.
|
||||
let sel = cx.wait_until(deadline);
|
||||
|
||||
match sel {
|
||||
Selected::Waiting => unreachable!(),
|
||||
Selected::Aborted | Selected::Disconnected => {
|
||||
self.senders.unregister(oper).unwrap();
|
||||
}
|
||||
Selected::Operation(_) => {}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to receive a message without blocking.
|
||||
pub(crate) fn try_recv(&self) -> Result<T, TryRecvError> {
|
||||
let token = &mut Token::default();
|
||||
|
||||
if self.start_recv(token) {
|
||||
unsafe { self.read(token).map_err(|_| TryRecvError::Disconnected) }
|
||||
} else {
|
||||
Err(TryRecvError::Empty)
|
||||
}
|
||||
}
|
||||
|
||||
/// Receives a message from the channel.
|
||||
pub(crate) fn recv(&self, deadline: Option<Instant>) -> Result<T, RecvTimeoutError> {
|
||||
let token = &mut Token::default();
|
||||
loop {
|
||||
// Try receiving a message several times.
|
||||
let backoff = Backoff::new();
|
||||
loop {
|
||||
if self.start_recv(token) {
|
||||
let res = unsafe { self.read(token) };
|
||||
return res.map_err(|_| RecvTimeoutError::Disconnected);
|
||||
}
|
||||
|
||||
if backoff.is_completed() {
|
||||
break;
|
||||
} else {
|
||||
backoff.snooze();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(d) = deadline {
|
||||
if Instant::now() >= d {
|
||||
return Err(RecvTimeoutError::Timeout);
|
||||
}
|
||||
}
|
||||
|
||||
Context::with(|cx| {
|
||||
// Prepare for blocking until a sender wakes us up.
|
||||
let oper = Operation::hook(token);
|
||||
self.receivers.register(oper, cx);
|
||||
|
||||
// Has the channel become ready just now?
|
||||
if !self.is_empty() || self.is_disconnected() {
|
||||
let _ = cx.try_select(Selected::Aborted);
|
||||
}
|
||||
|
||||
// Block the current thread.
|
||||
let sel = cx.wait_until(deadline);
|
||||
|
||||
match sel {
|
||||
Selected::Waiting => unreachable!(),
|
||||
Selected::Aborted | Selected::Disconnected => {
|
||||
self.receivers.unregister(oper).unwrap();
|
||||
// If the channel was disconnected, we still have to check for remaining
|
||||
// messages.
|
||||
}
|
||||
Selected::Operation(_) => {}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the current number of messages inside the channel.
|
||||
pub(crate) fn len(&self) -> usize {
|
||||
loop {
|
||||
// Load the tail, then load the head.
|
||||
let tail = self.tail.load(Ordering::SeqCst);
|
||||
let head = self.head.load(Ordering::SeqCst);
|
||||
|
||||
// If the tail didn't change, we've got consistent values to work with.
|
||||
if self.tail.load(Ordering::SeqCst) == tail {
|
||||
let hix = head & (self.mark_bit - 1);
|
||||
let tix = tail & (self.mark_bit - 1);
|
||||
|
||||
return if hix < tix {
|
||||
tix - hix
|
||||
} else if hix > tix {
|
||||
self.cap - hix + tix
|
||||
} else if (tail & !self.mark_bit) == head {
|
||||
0
|
||||
} else {
|
||||
self.cap
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the capacity of the channel.
|
||||
pub(crate) fn capacity(&self) -> Option<usize> {
|
||||
Some(self.cap)
|
||||
}
|
||||
|
||||
/// Disconnects the channel and wakes up all blocked senders and receivers.
|
||||
///
|
||||
/// Returns `true` if this call disconnected the channel.
|
||||
pub(crate) fn disconnect(&self) -> bool {
|
||||
let tail = self.tail.fetch_or(self.mark_bit, Ordering::SeqCst);
|
||||
|
||||
if tail & self.mark_bit == 0 {
|
||||
self.senders.disconnect();
|
||||
self.receivers.disconnect();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the channel is disconnected.
|
||||
pub(crate) fn is_disconnected(&self) -> bool {
|
||||
self.tail.load(Ordering::SeqCst) & self.mark_bit != 0
|
||||
}
|
||||
|
||||
/// Returns `true` if the channel is empty.
|
||||
pub(crate) fn is_empty(&self) -> bool {
|
||||
let head = self.head.load(Ordering::SeqCst);
|
||||
let tail = self.tail.load(Ordering::SeqCst);
|
||||
|
||||
// Is the tail equal to the head?
|
||||
//
|
||||
// Note: If the head changes just before we load the tail, that means there was a moment
|
||||
// when the channel was not empty, so it is safe to just return `false`.
|
||||
(tail & !self.mark_bit) == head
|
||||
}
|
||||
|
||||
/// Returns `true` if the channel is full.
|
||||
pub(crate) fn is_full(&self) -> bool {
|
||||
let tail = self.tail.load(Ordering::SeqCst);
|
||||
let head = self.head.load(Ordering::SeqCst);
|
||||
|
||||
// Is the head lagging one lap behind tail?
|
||||
//
|
||||
// Note: If the tail changes just before we load the head, that means there was a moment
|
||||
// when the channel was not full, so it is safe to just return `false`.
|
||||
head.wrapping_add(self.one_lap) == tail & !self.mark_bit
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for Channel<T> {
|
||||
fn drop(&mut self) {
|
||||
if mem::needs_drop::<T>() {
|
||||
// Get the index of the head.
|
||||
let head = *self.head.get_mut();
|
||||
let tail = *self.tail.get_mut();
|
||||
|
||||
let hix = head & (self.mark_bit - 1);
|
||||
let tix = tail & (self.mark_bit - 1);
|
||||
|
||||
let len = if hix < tix {
|
||||
tix - hix
|
||||
} else if hix > tix {
|
||||
self.cap - hix + tix
|
||||
} else if (tail & !self.mark_bit) == head {
|
||||
0
|
||||
} else {
|
||||
self.cap
|
||||
};
|
||||
|
||||
// Loop over all slots that hold a message and drop them.
|
||||
for i in 0..len {
|
||||
// Compute the index of the next slot holding a message.
|
||||
let index = if hix + i < self.cap {
|
||||
hix + i
|
||||
} else {
|
||||
hix + i - self.cap
|
||||
};
|
||||
|
||||
unsafe {
|
||||
debug_assert!(index < self.buffer.len());
|
||||
let slot = self.buffer.get_unchecked_mut(index);
|
||||
(*slot.msg.get()).assume_init_drop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Receiver handle to a channel.
|
||||
pub(crate) struct Receiver<'a, T>(&'a Channel<T>);
|
||||
|
||||
/// Sender handle to a channel.
|
||||
pub(crate) struct Sender<'a, T>(&'a Channel<T>);
|
||||
|
||||
impl<T> SelectHandle for Receiver<'_, T> {
|
||||
fn try_select(&self, token: &mut Token) -> bool {
|
||||
self.0.start_recv(token)
|
||||
}
|
||||
|
||||
fn deadline(&self) -> Option<Instant> {
|
||||
None
|
||||
}
|
||||
|
||||
fn register(&self, oper: Operation, cx: &Context) -> bool {
|
||||
self.0.receivers.register(oper, cx);
|
||||
self.is_ready()
|
||||
}
|
||||
|
||||
fn unregister(&self, oper: Operation) {
|
||||
self.0.receivers.unregister(oper);
|
||||
}
|
||||
|
||||
fn accept(&self, token: &mut Token, _cx: &Context) -> bool {
|
||||
self.try_select(token)
|
||||
}
|
||||
|
||||
fn is_ready(&self) -> bool {
|
||||
!self.0.is_empty() || self.0.is_disconnected()
|
||||
}
|
||||
|
||||
fn watch(&self, oper: Operation, cx: &Context) -> bool {
|
||||
self.0.receivers.watch(oper, cx);
|
||||
self.is_ready()
|
||||
}
|
||||
|
||||
fn unwatch(&self, oper: Operation) {
|
||||
self.0.receivers.unwatch(oper);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SelectHandle for Sender<'_, T> {
|
||||
fn try_select(&self, token: &mut Token) -> bool {
|
||||
self.0.start_send(token)
|
||||
}
|
||||
|
||||
fn deadline(&self) -> Option<Instant> {
|
||||
None
|
||||
}
|
||||
|
||||
fn register(&self, oper: Operation, cx: &Context) -> bool {
|
||||
self.0.senders.register(oper, cx);
|
||||
self.is_ready()
|
||||
}
|
||||
|
||||
fn unregister(&self, oper: Operation) {
|
||||
self.0.senders.unregister(oper);
|
||||
}
|
||||
|
||||
fn accept(&self, token: &mut Token, _cx: &Context) -> bool {
|
||||
self.try_select(token)
|
||||
}
|
||||
|
||||
fn is_ready(&self) -> bool {
|
||||
!self.0.is_full() || self.0.is_disconnected()
|
||||
}
|
||||
|
||||
fn watch(&self, oper: Operation, cx: &Context) -> bool {
|
||||
self.0.senders.watch(oper, cx);
|
||||
self.is_ready()
|
||||
}
|
||||
|
||||
fn unwatch(&self, oper: Operation) {
|
||||
self.0.senders.unwatch(oper);
|
||||
}
|
||||
}
|
||||
197
third-party/vendor/crossbeam-channel/src/flavors/at.rs
vendored
Normal file
197
third-party/vendor/crossbeam-channel/src/flavors/at.rs
vendored
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
//! Channel that delivers a message at a certain moment in time.
|
||||
//!
|
||||
//! Messages cannot be sent into this kind of channel; they are materialized on demand.
|
||||
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::thread;
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::err::{RecvTimeoutError, TryRecvError};
|
||||
use crate::select::{Operation, SelectHandle, Token};
|
||||
use crate::utils;
|
||||
|
||||
/// Result of a receive operation.
|
||||
pub(crate) type AtToken = Option<Instant>;
|
||||
|
||||
/// Channel that delivers a message at a certain moment in time
|
||||
pub(crate) struct Channel {
|
||||
/// The instant at which the message will be delivered.
|
||||
delivery_time: Instant,
|
||||
|
||||
/// `true` if the message has been received.
|
||||
received: AtomicBool,
|
||||
}
|
||||
|
||||
impl Channel {
|
||||
/// Creates a channel that delivers a message at a certain instant in time.
|
||||
#[inline]
|
||||
pub(crate) fn new_deadline(when: Instant) -> Self {
|
||||
Channel {
|
||||
delivery_time: when,
|
||||
received: AtomicBool::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to receive a message without blocking.
|
||||
#[inline]
|
||||
pub(crate) fn try_recv(&self) -> Result<Instant, TryRecvError> {
|
||||
// We use relaxed ordering because this is just an optional optimistic check.
|
||||
if self.received.load(Ordering::Relaxed) {
|
||||
// The message has already been received.
|
||||
return Err(TryRecvError::Empty);
|
||||
}
|
||||
|
||||
if Instant::now() < self.delivery_time {
|
||||
// The message was not delivered yet.
|
||||
return Err(TryRecvError::Empty);
|
||||
}
|
||||
|
||||
// Try receiving the message if it is still available.
|
||||
if !self.received.swap(true, Ordering::SeqCst) {
|
||||
// Success! Return delivery time as the message.
|
||||
Ok(self.delivery_time)
|
||||
} else {
|
||||
// The message was already received.
|
||||
Err(TryRecvError::Empty)
|
||||
}
|
||||
}
|
||||
|
||||
/// Receives a message from the channel.
|
||||
#[inline]
|
||||
pub(crate) fn recv(&self, deadline: Option<Instant>) -> Result<Instant, RecvTimeoutError> {
|
||||
// We use relaxed ordering because this is just an optional optimistic check.
|
||||
if self.received.load(Ordering::Relaxed) {
|
||||
// The message has already been received.
|
||||
utils::sleep_until(deadline);
|
||||
return Err(RecvTimeoutError::Timeout);
|
||||
}
|
||||
|
||||
// Wait until the message is received or the deadline is reached.
|
||||
loop {
|
||||
let now = Instant::now();
|
||||
|
||||
let deadline = match deadline {
|
||||
// Check if we can receive the next message.
|
||||
_ if now >= self.delivery_time => break,
|
||||
// Check if the timeout deadline has been reached.
|
||||
Some(d) if now >= d => return Err(RecvTimeoutError::Timeout),
|
||||
|
||||
// Sleep until one of the above happens
|
||||
Some(d) if d < self.delivery_time => d,
|
||||
_ => self.delivery_time,
|
||||
};
|
||||
|
||||
thread::sleep(deadline - now);
|
||||
}
|
||||
|
||||
// Try receiving the message if it is still available.
|
||||
if !self.received.swap(true, Ordering::SeqCst) {
|
||||
// Success! Return the message, which is the instant at which it was delivered.
|
||||
Ok(self.delivery_time)
|
||||
} else {
|
||||
// The message was already received. Block forever.
|
||||
utils::sleep_until(None);
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads a message from the channel.
|
||||
#[inline]
|
||||
pub(crate) unsafe fn read(&self, token: &mut Token) -> Result<Instant, ()> {
|
||||
token.at.ok_or(())
|
||||
}
|
||||
|
||||
/// Returns `true` if the channel is empty.
|
||||
#[inline]
|
||||
pub(crate) fn is_empty(&self) -> bool {
|
||||
// We use relaxed ordering because this is just an optional optimistic check.
|
||||
if self.received.load(Ordering::Relaxed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the delivery time hasn't been reached yet, the channel is empty.
|
||||
if Instant::now() < self.delivery_time {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The delivery time has been reached. The channel is empty only if the message has already
|
||||
// been received.
|
||||
self.received.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
/// Returns `true` if the channel is full.
|
||||
#[inline]
|
||||
pub(crate) fn is_full(&self) -> bool {
|
||||
!self.is_empty()
|
||||
}
|
||||
|
||||
/// Returns the number of messages in the channel.
|
||||
#[inline]
|
||||
pub(crate) fn len(&self) -> usize {
|
||||
if self.is_empty() {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the capacity of the channel.
|
||||
#[inline]
|
||||
pub(crate) fn capacity(&self) -> Option<usize> {
|
||||
Some(1)
|
||||
}
|
||||
}
|
||||
|
||||
impl SelectHandle for Channel {
|
||||
#[inline]
|
||||
fn try_select(&self, token: &mut Token) -> bool {
|
||||
match self.try_recv() {
|
||||
Ok(msg) => {
|
||||
token.at = Some(msg);
|
||||
true
|
||||
}
|
||||
Err(TryRecvError::Disconnected) => {
|
||||
token.at = None;
|
||||
true
|
||||
}
|
||||
Err(TryRecvError::Empty) => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn deadline(&self) -> Option<Instant> {
|
||||
// We use relaxed ordering because this is just an optional optimistic check.
|
||||
if self.received.load(Ordering::Relaxed) {
|
||||
None
|
||||
} else {
|
||||
Some(self.delivery_time)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn register(&self, _oper: Operation, _cx: &Context) -> bool {
|
||||
self.is_ready()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn unregister(&self, _oper: Operation) {}
|
||||
|
||||
#[inline]
|
||||
fn accept(&self, token: &mut Token, _cx: &Context) -> bool {
|
||||
self.try_select(token)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_ready(&self) -> bool {
|
||||
!self.is_empty()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn watch(&self, _oper: Operation, _cx: &Context) -> bool {
|
||||
self.is_ready()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn unwatch(&self, _oper: Operation) {}
|
||||
}
|
||||
755
third-party/vendor/crossbeam-channel/src/flavors/list.rs
vendored
Normal file
755
third-party/vendor/crossbeam-channel/src/flavors/list.rs
vendored
Normal file
|
|
@ -0,0 +1,755 @@
|
|||
//! Unbounded channel implemented as a linked list.
|
||||
|
||||
use std::boxed::Box;
|
||||
use std::cell::UnsafeCell;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::ptr;
|
||||
use std::sync::atomic::{self, AtomicPtr, AtomicUsize, Ordering};
|
||||
use std::time::Instant;
|
||||
|
||||
use crossbeam_utils::{Backoff, CachePadded};
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::err::{RecvTimeoutError, SendTimeoutError, TryRecvError, TrySendError};
|
||||
use crate::select::{Operation, SelectHandle, Selected, Token};
|
||||
use crate::waker::SyncWaker;
|
||||
|
||||
// TODO(stjepang): Once we bump the minimum required Rust version to 1.28 or newer, re-apply the
|
||||
// following changes by @kleimkuhler:
|
||||
//
|
||||
// 1. https://github.com/crossbeam-rs/crossbeam-channel/pull/100
|
||||
// 2. https://github.com/crossbeam-rs/crossbeam-channel/pull/101
|
||||
|
||||
// Bits indicating the state of a slot:
|
||||
// * If a message has been written into the slot, `WRITE` is set.
|
||||
// * If a message has been read from the slot, `READ` is set.
|
||||
// * If the block is being destroyed, `DESTROY` is set.
|
||||
const WRITE: usize = 1;
|
||||
const READ: usize = 2;
|
||||
const DESTROY: usize = 4;
|
||||
|
||||
// Each block covers one "lap" of indices.
|
||||
const LAP: usize = 32;
|
||||
// The maximum number of messages a block can hold.
|
||||
const BLOCK_CAP: usize = LAP - 1;
|
||||
// How many lower bits are reserved for metadata.
|
||||
const SHIFT: usize = 1;
|
||||
// Has two different purposes:
|
||||
// * If set in head, indicates that the block is not the last one.
|
||||
// * If set in tail, indicates that the channel is disconnected.
|
||||
const MARK_BIT: usize = 1;
|
||||
|
||||
/// A slot in a block.
|
||||
struct Slot<T> {
|
||||
/// The message.
|
||||
msg: UnsafeCell<MaybeUninit<T>>,
|
||||
|
||||
/// The state of the slot.
|
||||
state: AtomicUsize,
|
||||
}
|
||||
|
||||
impl<T> Slot<T> {
|
||||
const UNINIT: Self = Self {
|
||||
msg: UnsafeCell::new(MaybeUninit::uninit()),
|
||||
state: AtomicUsize::new(0),
|
||||
};
|
||||
|
||||
/// Waits until a message is written into the slot.
|
||||
fn wait_write(&self) {
|
||||
let backoff = Backoff::new();
|
||||
while self.state.load(Ordering::Acquire) & WRITE == 0 {
|
||||
backoff.snooze();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A block in a linked list.
|
||||
///
|
||||
/// Each block in the list can hold up to `BLOCK_CAP` messages.
|
||||
struct Block<T> {
|
||||
/// The next block in the linked list.
|
||||
next: AtomicPtr<Block<T>>,
|
||||
|
||||
/// Slots for messages.
|
||||
slots: [Slot<T>; BLOCK_CAP],
|
||||
}
|
||||
|
||||
impl<T> Block<T> {
|
||||
/// Creates an empty block.
|
||||
fn new() -> Block<T> {
|
||||
Self {
|
||||
next: AtomicPtr::new(ptr::null_mut()),
|
||||
slots: [Slot::UNINIT; BLOCK_CAP],
|
||||
}
|
||||
}
|
||||
|
||||
/// Waits until the next pointer is set.
|
||||
fn wait_next(&self) -> *mut Block<T> {
|
||||
let backoff = Backoff::new();
|
||||
loop {
|
||||
let next = self.next.load(Ordering::Acquire);
|
||||
if !next.is_null() {
|
||||
return next;
|
||||
}
|
||||
backoff.snooze();
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the `DESTROY` bit in slots starting from `start` and destroys the block.
|
||||
unsafe fn destroy(this: *mut Block<T>, start: usize) {
|
||||
// It is not necessary to set the `DESTROY` bit in the last slot because that slot has
|
||||
// begun destruction of the block.
|
||||
for i in start..BLOCK_CAP - 1 {
|
||||
let slot = (*this).slots.get_unchecked(i);
|
||||
|
||||
// Mark the `DESTROY` bit if a thread is still using the slot.
|
||||
if slot.state.load(Ordering::Acquire) & READ == 0
|
||||
&& slot.state.fetch_or(DESTROY, Ordering::AcqRel) & READ == 0
|
||||
{
|
||||
// If a thread is still using the slot, it will continue destruction of the block.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// No thread is using the block, now it is safe to destroy it.
|
||||
drop(Box::from_raw(this));
|
||||
}
|
||||
}
|
||||
|
||||
/// A position in a channel.
|
||||
#[derive(Debug)]
|
||||
struct Position<T> {
|
||||
/// The index in the channel.
|
||||
index: AtomicUsize,
|
||||
|
||||
/// The block in the linked list.
|
||||
block: AtomicPtr<Block<T>>,
|
||||
}
|
||||
|
||||
/// The token type for the list flavor.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ListToken {
|
||||
/// The block of slots.
|
||||
block: *const u8,
|
||||
|
||||
/// The offset into the block.
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
impl Default for ListToken {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
ListToken {
|
||||
block: ptr::null(),
|
||||
offset: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Unbounded channel implemented as a linked list.
|
||||
///
|
||||
/// Each message sent into the channel is assigned a sequence number, i.e. an index. Indices are
|
||||
/// represented as numbers of type `usize` and wrap on overflow.
|
||||
///
|
||||
/// Consecutive messages are grouped into blocks in order to put less pressure on the allocator and
|
||||
/// improve cache efficiency.
|
||||
pub(crate) struct Channel<T> {
|
||||
/// The head of the channel.
|
||||
head: CachePadded<Position<T>>,
|
||||
|
||||
/// The tail of the channel.
|
||||
tail: CachePadded<Position<T>>,
|
||||
|
||||
/// Receivers waiting while the channel is empty and not disconnected.
|
||||
receivers: SyncWaker,
|
||||
|
||||
/// Indicates that dropping a `Channel<T>` may drop messages of type `T`.
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> Channel<T> {
|
||||
/// Creates a new unbounded channel.
|
||||
pub(crate) fn new() -> Self {
|
||||
Channel {
|
||||
head: CachePadded::new(Position {
|
||||
block: AtomicPtr::new(ptr::null_mut()),
|
||||
index: AtomicUsize::new(0),
|
||||
}),
|
||||
tail: CachePadded::new(Position {
|
||||
block: AtomicPtr::new(ptr::null_mut()),
|
||||
index: AtomicUsize::new(0),
|
||||
}),
|
||||
receivers: SyncWaker::new(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a receiver handle to the channel.
|
||||
pub(crate) fn receiver(&self) -> Receiver<'_, T> {
|
||||
Receiver(self)
|
||||
}
|
||||
|
||||
/// Returns a sender handle to the channel.
|
||||
pub(crate) fn sender(&self) -> Sender<'_, T> {
|
||||
Sender(self)
|
||||
}
|
||||
|
||||
/// Attempts to reserve a slot for sending a message.
|
||||
fn start_send(&self, token: &mut Token) -> bool {
|
||||
let backoff = Backoff::new();
|
||||
let mut tail = self.tail.index.load(Ordering::Acquire);
|
||||
let mut block = self.tail.block.load(Ordering::Acquire);
|
||||
let mut next_block = None;
|
||||
|
||||
loop {
|
||||
// Check if the channel is disconnected.
|
||||
if tail & MARK_BIT != 0 {
|
||||
token.list.block = ptr::null();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Calculate the offset of the index into the block.
|
||||
let offset = (tail >> SHIFT) % LAP;
|
||||
|
||||
// If we reached the end of the block, wait until the next one is installed.
|
||||
if offset == BLOCK_CAP {
|
||||
backoff.snooze();
|
||||
tail = self.tail.index.load(Ordering::Acquire);
|
||||
block = self.tail.block.load(Ordering::Acquire);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we're going to have to install the next block, allocate it in advance in order to
|
||||
// make the wait for other threads as short as possible.
|
||||
if offset + 1 == BLOCK_CAP && next_block.is_none() {
|
||||
next_block = Some(Box::new(Block::<T>::new()));
|
||||
}
|
||||
|
||||
// If this is the first message to be sent into the channel, we need to allocate the
|
||||
// first block and install it.
|
||||
if block.is_null() {
|
||||
let new = Box::into_raw(Box::new(Block::<T>::new()));
|
||||
|
||||
if self
|
||||
.tail
|
||||
.block
|
||||
.compare_exchange(block, new, Ordering::Release, Ordering::Relaxed)
|
||||
.is_ok()
|
||||
{
|
||||
self.head.block.store(new, Ordering::Release);
|
||||
block = new;
|
||||
} else {
|
||||
next_block = unsafe { Some(Box::from_raw(new)) };
|
||||
tail = self.tail.index.load(Ordering::Acquire);
|
||||
block = self.tail.block.load(Ordering::Acquire);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let new_tail = tail + (1 << SHIFT);
|
||||
|
||||
// Try advancing the tail forward.
|
||||
match self.tail.index.compare_exchange_weak(
|
||||
tail,
|
||||
new_tail,
|
||||
Ordering::SeqCst,
|
||||
Ordering::Acquire,
|
||||
) {
|
||||
Ok(_) => unsafe {
|
||||
// If we've reached the end of the block, install the next one.
|
||||
if offset + 1 == BLOCK_CAP {
|
||||
let next_block = Box::into_raw(next_block.unwrap());
|
||||
self.tail.block.store(next_block, Ordering::Release);
|
||||
self.tail.index.fetch_add(1 << SHIFT, Ordering::Release);
|
||||
(*block).next.store(next_block, Ordering::Release);
|
||||
}
|
||||
|
||||
token.list.block = block as *const u8;
|
||||
token.list.offset = offset;
|
||||
return true;
|
||||
},
|
||||
Err(t) => {
|
||||
tail = t;
|
||||
block = self.tail.block.load(Ordering::Acquire);
|
||||
backoff.spin();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a message into the channel.
|
||||
pub(crate) unsafe fn write(&self, token: &mut Token, msg: T) -> Result<(), T> {
|
||||
// If there is no slot, the channel is disconnected.
|
||||
if token.list.block.is_null() {
|
||||
return Err(msg);
|
||||
}
|
||||
|
||||
// Write the message into the slot.
|
||||
let block = token.list.block.cast::<Block<T>>();
|
||||
let offset = token.list.offset;
|
||||
let slot = (*block).slots.get_unchecked(offset);
|
||||
slot.msg.get().write(MaybeUninit::new(msg));
|
||||
slot.state.fetch_or(WRITE, Ordering::Release);
|
||||
|
||||
// Wake a sleeping receiver.
|
||||
self.receivers.notify();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Attempts to reserve a slot for receiving a message.
|
||||
fn start_recv(&self, token: &mut Token) -> bool {
|
||||
let backoff = Backoff::new();
|
||||
let mut head = self.head.index.load(Ordering::Acquire);
|
||||
let mut block = self.head.block.load(Ordering::Acquire);
|
||||
|
||||
loop {
|
||||
// Calculate the offset of the index into the block.
|
||||
let offset = (head >> SHIFT) % LAP;
|
||||
|
||||
// If we reached the end of the block, wait until the next one is installed.
|
||||
if offset == BLOCK_CAP {
|
||||
backoff.snooze();
|
||||
head = self.head.index.load(Ordering::Acquire);
|
||||
block = self.head.block.load(Ordering::Acquire);
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut new_head = head + (1 << SHIFT);
|
||||
|
||||
if new_head & MARK_BIT == 0 {
|
||||
atomic::fence(Ordering::SeqCst);
|
||||
let tail = self.tail.index.load(Ordering::Relaxed);
|
||||
|
||||
// If the tail equals the head, that means the channel is empty.
|
||||
if head >> SHIFT == tail >> SHIFT {
|
||||
// If the channel is disconnected...
|
||||
if tail & MARK_BIT != 0 {
|
||||
// ...then receive an error.
|
||||
token.list.block = ptr::null();
|
||||
return true;
|
||||
} else {
|
||||
// Otherwise, the receive operation is not ready.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If head and tail are not in the same block, set `MARK_BIT` in head.
|
||||
if (head >> SHIFT) / LAP != (tail >> SHIFT) / LAP {
|
||||
new_head |= MARK_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
// The block can be null here only if the first message is being sent into the channel.
|
||||
// In that case, just wait until it gets initialized.
|
||||
if block.is_null() {
|
||||
backoff.snooze();
|
||||
head = self.head.index.load(Ordering::Acquire);
|
||||
block = self.head.block.load(Ordering::Acquire);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Try moving the head index forward.
|
||||
match self.head.index.compare_exchange_weak(
|
||||
head,
|
||||
new_head,
|
||||
Ordering::SeqCst,
|
||||
Ordering::Acquire,
|
||||
) {
|
||||
Ok(_) => unsafe {
|
||||
// If we've reached the end of the block, move to the next one.
|
||||
if offset + 1 == BLOCK_CAP {
|
||||
let next = (*block).wait_next();
|
||||
let mut next_index = (new_head & !MARK_BIT).wrapping_add(1 << SHIFT);
|
||||
if !(*next).next.load(Ordering::Relaxed).is_null() {
|
||||
next_index |= MARK_BIT;
|
||||
}
|
||||
|
||||
self.head.block.store(next, Ordering::Release);
|
||||
self.head.index.store(next_index, Ordering::Release);
|
||||
}
|
||||
|
||||
token.list.block = block as *const u8;
|
||||
token.list.offset = offset;
|
||||
return true;
|
||||
},
|
||||
Err(h) => {
|
||||
head = h;
|
||||
block = self.head.block.load(Ordering::Acquire);
|
||||
backoff.spin();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads a message from the channel.
|
||||
pub(crate) unsafe fn read(&self, token: &mut Token) -> Result<T, ()> {
|
||||
if token.list.block.is_null() {
|
||||
// The channel is disconnected.
|
||||
return Err(());
|
||||
}
|
||||
|
||||
// Read the message.
|
||||
let block = token.list.block as *mut Block<T>;
|
||||
let offset = token.list.offset;
|
||||
let slot = (*block).slots.get_unchecked(offset);
|
||||
slot.wait_write();
|
||||
let msg = slot.msg.get().read().assume_init();
|
||||
|
||||
// Destroy the block if we've reached the end, or if another thread wanted to destroy but
|
||||
// couldn't because we were busy reading from the slot.
|
||||
if offset + 1 == BLOCK_CAP {
|
||||
Block::destroy(block, 0);
|
||||
} else if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 {
|
||||
Block::destroy(block, offset + 1);
|
||||
}
|
||||
|
||||
Ok(msg)
|
||||
}
|
||||
|
||||
/// Attempts to send a message into the channel.
|
||||
pub(crate) fn try_send(&self, msg: T) -> Result<(), TrySendError<T>> {
|
||||
self.send(msg, None).map_err(|err| match err {
|
||||
SendTimeoutError::Disconnected(msg) => TrySendError::Disconnected(msg),
|
||||
SendTimeoutError::Timeout(_) => unreachable!(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Sends a message into the channel.
|
||||
pub(crate) fn send(
|
||||
&self,
|
||||
msg: T,
|
||||
_deadline: Option<Instant>,
|
||||
) -> Result<(), SendTimeoutError<T>> {
|
||||
let token = &mut Token::default();
|
||||
assert!(self.start_send(token));
|
||||
unsafe {
|
||||
self.write(token, msg)
|
||||
.map_err(SendTimeoutError::Disconnected)
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to receive a message without blocking.
|
||||
pub(crate) fn try_recv(&self) -> Result<T, TryRecvError> {
|
||||
let token = &mut Token::default();
|
||||
|
||||
if self.start_recv(token) {
|
||||
unsafe { self.read(token).map_err(|_| TryRecvError::Disconnected) }
|
||||
} else {
|
||||
Err(TryRecvError::Empty)
|
||||
}
|
||||
}
|
||||
|
||||
/// Receives a message from the channel.
|
||||
pub(crate) fn recv(&self, deadline: Option<Instant>) -> Result<T, RecvTimeoutError> {
|
||||
let token = &mut Token::default();
|
||||
loop {
|
||||
// Try receiving a message several times.
|
||||
let backoff = Backoff::new();
|
||||
loop {
|
||||
if self.start_recv(token) {
|
||||
unsafe {
|
||||
return self.read(token).map_err(|_| RecvTimeoutError::Disconnected);
|
||||
}
|
||||
}
|
||||
|
||||
if backoff.is_completed() {
|
||||
break;
|
||||
} else {
|
||||
backoff.snooze();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(d) = deadline {
|
||||
if Instant::now() >= d {
|
||||
return Err(RecvTimeoutError::Timeout);
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare for blocking until a sender wakes us up.
|
||||
Context::with(|cx| {
|
||||
let oper = Operation::hook(token);
|
||||
self.receivers.register(oper, cx);
|
||||
|
||||
// Has the channel become ready just now?
|
||||
if !self.is_empty() || self.is_disconnected() {
|
||||
let _ = cx.try_select(Selected::Aborted);
|
||||
}
|
||||
|
||||
// Block the current thread.
|
||||
let sel = cx.wait_until(deadline);
|
||||
|
||||
match sel {
|
||||
Selected::Waiting => unreachable!(),
|
||||
Selected::Aborted | Selected::Disconnected => {
|
||||
self.receivers.unregister(oper).unwrap();
|
||||
// If the channel was disconnected, we still have to check for remaining
|
||||
// messages.
|
||||
}
|
||||
Selected::Operation(_) => {}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the current number of messages inside the channel.
|
||||
pub(crate) fn len(&self) -> usize {
|
||||
loop {
|
||||
// Load the tail index, then load the head index.
|
||||
let mut tail = self.tail.index.load(Ordering::SeqCst);
|
||||
let mut head = self.head.index.load(Ordering::SeqCst);
|
||||
|
||||
// If the tail index didn't change, we've got consistent indices to work with.
|
||||
if self.tail.index.load(Ordering::SeqCst) == tail {
|
||||
// Erase the lower bits.
|
||||
tail &= !((1 << SHIFT) - 1);
|
||||
head &= !((1 << SHIFT) - 1);
|
||||
|
||||
// Fix up indices if they fall onto block ends.
|
||||
if (tail >> SHIFT) & (LAP - 1) == LAP - 1 {
|
||||
tail = tail.wrapping_add(1 << SHIFT);
|
||||
}
|
||||
if (head >> SHIFT) & (LAP - 1) == LAP - 1 {
|
||||
head = head.wrapping_add(1 << SHIFT);
|
||||
}
|
||||
|
||||
// Rotate indices so that head falls into the first block.
|
||||
let lap = (head >> SHIFT) / LAP;
|
||||
tail = tail.wrapping_sub((lap * LAP) << SHIFT);
|
||||
head = head.wrapping_sub((lap * LAP) << SHIFT);
|
||||
|
||||
// Remove the lower bits.
|
||||
tail >>= SHIFT;
|
||||
head >>= SHIFT;
|
||||
|
||||
// Return the difference minus the number of blocks between tail and head.
|
||||
return tail - head - tail / LAP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the capacity of the channel.
|
||||
pub(crate) fn capacity(&self) -> Option<usize> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Disconnects senders and wakes up all blocked receivers.
|
||||
///
|
||||
/// Returns `true` if this call disconnected the channel.
|
||||
pub(crate) fn disconnect_senders(&self) -> bool {
|
||||
let tail = self.tail.index.fetch_or(MARK_BIT, Ordering::SeqCst);
|
||||
|
||||
if tail & MARK_BIT == 0 {
|
||||
self.receivers.disconnect();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Disconnects receivers.
|
||||
///
|
||||
/// Returns `true` if this call disconnected the channel.
|
||||
pub(crate) fn disconnect_receivers(&self) -> bool {
|
||||
let tail = self.tail.index.fetch_or(MARK_BIT, Ordering::SeqCst);
|
||||
|
||||
if tail & MARK_BIT == 0 {
|
||||
// If receivers are dropped first, discard all messages to free
|
||||
// memory eagerly.
|
||||
self.discard_all_messages();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Discards all messages.
|
||||
///
|
||||
/// This method should only be called when all receivers are dropped.
|
||||
fn discard_all_messages(&self) {
|
||||
let backoff = Backoff::new();
|
||||
let mut tail = self.tail.index.load(Ordering::Acquire);
|
||||
loop {
|
||||
let offset = (tail >> SHIFT) % LAP;
|
||||
if offset != BLOCK_CAP {
|
||||
break;
|
||||
}
|
||||
|
||||
// New updates to tail will be rejected by MARK_BIT and aborted unless it's
|
||||
// at boundary. We need to wait for the updates take affect otherwise there
|
||||
// can be memory leaks.
|
||||
backoff.snooze();
|
||||
tail = self.tail.index.load(Ordering::Acquire);
|
||||
}
|
||||
|
||||
let mut head = self.head.index.load(Ordering::Acquire);
|
||||
let mut block = self.head.block.swap(ptr::null_mut(), Ordering::AcqRel);
|
||||
|
||||
// If we're going to be dropping messages we need to synchronize with initialization
|
||||
if head >> SHIFT != tail >> SHIFT {
|
||||
// The block can be null here only if a sender is in the process of initializing the
|
||||
// channel while another sender managed to send a message by inserting it into the
|
||||
// semi-initialized channel and advanced the tail.
|
||||
// In that case, just wait until it gets initialized.
|
||||
while block.is_null() {
|
||||
backoff.snooze();
|
||||
block = self.head.block.load(Ordering::Acquire);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
// Drop all messages between head and tail and deallocate the heap-allocated blocks.
|
||||
while head >> SHIFT != tail >> SHIFT {
|
||||
let offset = (head >> SHIFT) % LAP;
|
||||
|
||||
if offset < BLOCK_CAP {
|
||||
// Drop the message in the slot.
|
||||
let slot = (*block).slots.get_unchecked(offset);
|
||||
slot.wait_write();
|
||||
(*slot.msg.get()).assume_init_drop();
|
||||
} else {
|
||||
(*block).wait_next();
|
||||
// Deallocate the block and move to the next one.
|
||||
let next = (*block).next.load(Ordering::Acquire);
|
||||
drop(Box::from_raw(block));
|
||||
block = next;
|
||||
}
|
||||
|
||||
head = head.wrapping_add(1 << SHIFT);
|
||||
}
|
||||
|
||||
// Deallocate the last remaining block.
|
||||
if !block.is_null() {
|
||||
drop(Box::from_raw(block));
|
||||
}
|
||||
}
|
||||
head &= !MARK_BIT;
|
||||
self.head.index.store(head, Ordering::Release);
|
||||
}
|
||||
|
||||
/// Returns `true` if the channel is disconnected.
|
||||
pub(crate) fn is_disconnected(&self) -> bool {
|
||||
self.tail.index.load(Ordering::SeqCst) & MARK_BIT != 0
|
||||
}
|
||||
|
||||
/// Returns `true` if the channel is empty.
|
||||
pub(crate) fn is_empty(&self) -> bool {
|
||||
let head = self.head.index.load(Ordering::SeqCst);
|
||||
let tail = self.tail.index.load(Ordering::SeqCst);
|
||||
head >> SHIFT == tail >> SHIFT
|
||||
}
|
||||
|
||||
/// Returns `true` if the channel is full.
|
||||
pub(crate) fn is_full(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for Channel<T> {
|
||||
fn drop(&mut self) {
|
||||
let mut head = *self.head.index.get_mut();
|
||||
let mut tail = *self.tail.index.get_mut();
|
||||
let mut block = *self.head.block.get_mut();
|
||||
|
||||
// Erase the lower bits.
|
||||
head &= !((1 << SHIFT) - 1);
|
||||
tail &= !((1 << SHIFT) - 1);
|
||||
|
||||
unsafe {
|
||||
// Drop all messages between head and tail and deallocate the heap-allocated blocks.
|
||||
while head != tail {
|
||||
let offset = (head >> SHIFT) % LAP;
|
||||
|
||||
if offset < BLOCK_CAP {
|
||||
// Drop the message in the slot.
|
||||
let slot = (*block).slots.get_unchecked(offset);
|
||||
(*slot.msg.get()).assume_init_drop();
|
||||
} else {
|
||||
// Deallocate the block and move to the next one.
|
||||
let next = *(*block).next.get_mut();
|
||||
drop(Box::from_raw(block));
|
||||
block = next;
|
||||
}
|
||||
|
||||
head = head.wrapping_add(1 << SHIFT);
|
||||
}
|
||||
|
||||
// Deallocate the last remaining block.
|
||||
if !block.is_null() {
|
||||
drop(Box::from_raw(block));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Receiver handle to a channel.
|
||||
pub(crate) struct Receiver<'a, T>(&'a Channel<T>);
|
||||
|
||||
/// Sender handle to a channel.
|
||||
pub(crate) struct Sender<'a, T>(&'a Channel<T>);
|
||||
|
||||
impl<T> SelectHandle for Receiver<'_, T> {
|
||||
fn try_select(&self, token: &mut Token) -> bool {
|
||||
self.0.start_recv(token)
|
||||
}
|
||||
|
||||
fn deadline(&self) -> Option<Instant> {
|
||||
None
|
||||
}
|
||||
|
||||
fn register(&self, oper: Operation, cx: &Context) -> bool {
|
||||
self.0.receivers.register(oper, cx);
|
||||
self.is_ready()
|
||||
}
|
||||
|
||||
fn unregister(&self, oper: Operation) {
|
||||
self.0.receivers.unregister(oper);
|
||||
}
|
||||
|
||||
fn accept(&self, token: &mut Token, _cx: &Context) -> bool {
|
||||
self.try_select(token)
|
||||
}
|
||||
|
||||
fn is_ready(&self) -> bool {
|
||||
!self.0.is_empty() || self.0.is_disconnected()
|
||||
}
|
||||
|
||||
fn watch(&self, oper: Operation, cx: &Context) -> bool {
|
||||
self.0.receivers.watch(oper, cx);
|
||||
self.is_ready()
|
||||
}
|
||||
|
||||
fn unwatch(&self, oper: Operation) {
|
||||
self.0.receivers.unwatch(oper);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SelectHandle for Sender<'_, T> {
|
||||
fn try_select(&self, token: &mut Token) -> bool {
|
||||
self.0.start_send(token)
|
||||
}
|
||||
|
||||
fn deadline(&self) -> Option<Instant> {
|
||||
None
|
||||
}
|
||||
|
||||
fn register(&self, _oper: Operation, _cx: &Context) -> bool {
|
||||
self.is_ready()
|
||||
}
|
||||
|
||||
fn unregister(&self, _oper: Operation) {}
|
||||
|
||||
fn accept(&self, token: &mut Token, _cx: &Context) -> bool {
|
||||
self.try_select(token)
|
||||
}
|
||||
|
||||
fn is_ready(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn watch(&self, _oper: Operation, _cx: &Context) -> bool {
|
||||
self.is_ready()
|
||||
}
|
||||
|
||||
fn unwatch(&self, _oper: Operation) {}
|
||||
}
|
||||
17
third-party/vendor/crossbeam-channel/src/flavors/mod.rs
vendored
Normal file
17
third-party/vendor/crossbeam-channel/src/flavors/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
//! Channel flavors.
|
||||
//!
|
||||
//! There are six flavors:
|
||||
//!
|
||||
//! 1. `at` - Channel that delivers a message after a certain amount of time.
|
||||
//! 2. `array` - Bounded channel based on a preallocated array.
|
||||
//! 3. `list` - Unbounded channel implemented as a linked list.
|
||||
//! 4. `never` - Channel that never delivers messages.
|
||||
//! 5. `tick` - Channel that delivers messages periodically.
|
||||
//! 6. `zero` - Zero-capacity channel.
|
||||
|
||||
pub(crate) mod array;
|
||||
pub(crate) mod at;
|
||||
pub(crate) mod list;
|
||||
pub(crate) mod never;
|
||||
pub(crate) mod tick;
|
||||
pub(crate) mod zero;
|
||||
110
third-party/vendor/crossbeam-channel/src/flavors/never.rs
vendored
Normal file
110
third-party/vendor/crossbeam-channel/src/flavors/never.rs
vendored
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
//! Channel that never delivers messages.
|
||||
//!
|
||||
//! Messages cannot be sent into this kind of channel.
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::err::{RecvTimeoutError, TryRecvError};
|
||||
use crate::select::{Operation, SelectHandle, Token};
|
||||
use crate::utils;
|
||||
|
||||
/// This flavor doesn't need a token.
|
||||
pub(crate) type NeverToken = ();
|
||||
|
||||
/// Channel that never delivers messages.
|
||||
pub(crate) struct Channel<T> {
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> Channel<T> {
|
||||
/// Creates a channel that never delivers messages.
|
||||
#[inline]
|
||||
pub(crate) fn new() -> Self {
|
||||
Channel {
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to receive a message without blocking.
|
||||
#[inline]
|
||||
pub(crate) fn try_recv(&self) -> Result<T, TryRecvError> {
|
||||
Err(TryRecvError::Empty)
|
||||
}
|
||||
|
||||
/// Receives a message from the channel.
|
||||
#[inline]
|
||||
pub(crate) fn recv(&self, deadline: Option<Instant>) -> Result<T, RecvTimeoutError> {
|
||||
utils::sleep_until(deadline);
|
||||
Err(RecvTimeoutError::Timeout)
|
||||
}
|
||||
|
||||
/// Reads a message from the channel.
|
||||
#[inline]
|
||||
pub(crate) unsafe fn read(&self, _token: &mut Token) -> Result<T, ()> {
|
||||
Err(())
|
||||
}
|
||||
|
||||
/// Returns `true` if the channel is empty.
|
||||
#[inline]
|
||||
pub(crate) fn is_empty(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Returns `true` if the channel is full.
|
||||
#[inline]
|
||||
pub(crate) fn is_full(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Returns the number of messages in the channel.
|
||||
#[inline]
|
||||
pub(crate) fn len(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
/// Returns the capacity of the channel.
|
||||
#[inline]
|
||||
pub(crate) fn capacity(&self) -> Option<usize> {
|
||||
Some(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SelectHandle for Channel<T> {
|
||||
#[inline]
|
||||
fn try_select(&self, _token: &mut Token) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn deadline(&self) -> Option<Instant> {
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn register(&self, _oper: Operation, _cx: &Context) -> bool {
|
||||
self.is_ready()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn unregister(&self, _oper: Operation) {}
|
||||
|
||||
#[inline]
|
||||
fn accept(&self, token: &mut Token, _cx: &Context) -> bool {
|
||||
self.try_select(token)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_ready(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn watch(&self, _oper: Operation, _cx: &Context) -> bool {
|
||||
self.is_ready()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn unwatch(&self, _oper: Operation) {}
|
||||
}
|
||||
167
third-party/vendor/crossbeam-channel/src/flavors/tick.rs
vendored
Normal file
167
third-party/vendor/crossbeam-channel/src/flavors/tick.rs
vendored
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
//! Channel that delivers messages periodically.
|
||||
//!
|
||||
//! Messages cannot be sent into this kind of channel; they are materialized on demand.
|
||||
|
||||
use std::thread;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::err::{RecvTimeoutError, TryRecvError};
|
||||
use crate::select::{Operation, SelectHandle, Token};
|
||||
|
||||
/// Result of a receive operation.
|
||||
pub(crate) type TickToken = Option<Instant>;
|
||||
|
||||
/// Channel that delivers messages periodically.
|
||||
pub(crate) struct Channel {
|
||||
/// The instant at which the next message will be delivered.
|
||||
delivery_time: AtomicCell<Instant>,
|
||||
|
||||
/// The time interval in which messages get delivered.
|
||||
duration: Duration,
|
||||
}
|
||||
|
||||
impl Channel {
|
||||
/// Creates a channel that delivers messages periodically.
|
||||
#[inline]
|
||||
pub(crate) fn new(delivery_time: Instant, dur: Duration) -> Self {
|
||||
Channel {
|
||||
delivery_time: AtomicCell::new(delivery_time),
|
||||
duration: dur,
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to receive a message without blocking.
|
||||
#[inline]
|
||||
pub(crate) fn try_recv(&self) -> Result<Instant, TryRecvError> {
|
||||
loop {
|
||||
let now = Instant::now();
|
||||
let delivery_time = self.delivery_time.load();
|
||||
|
||||
if now < delivery_time {
|
||||
return Err(TryRecvError::Empty);
|
||||
}
|
||||
|
||||
if self
|
||||
.delivery_time
|
||||
.compare_exchange(delivery_time, now + self.duration)
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(delivery_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Receives a message from the channel.
|
||||
#[inline]
|
||||
pub(crate) fn recv(&self, deadline: Option<Instant>) -> Result<Instant, RecvTimeoutError> {
|
||||
loop {
|
||||
let delivery_time = self.delivery_time.load();
|
||||
let now = Instant::now();
|
||||
|
||||
if let Some(d) = deadline {
|
||||
if d < delivery_time {
|
||||
if now < d {
|
||||
thread::sleep(d - now);
|
||||
}
|
||||
return Err(RecvTimeoutError::Timeout);
|
||||
}
|
||||
}
|
||||
|
||||
if self
|
||||
.delivery_time
|
||||
.compare_exchange(delivery_time, delivery_time.max(now) + self.duration)
|
||||
.is_ok()
|
||||
{
|
||||
if now < delivery_time {
|
||||
thread::sleep(delivery_time - now);
|
||||
}
|
||||
return Ok(delivery_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads a message from the channel.
|
||||
#[inline]
|
||||
pub(crate) unsafe fn read(&self, token: &mut Token) -> Result<Instant, ()> {
|
||||
token.tick.ok_or(())
|
||||
}
|
||||
|
||||
/// Returns `true` if the channel is empty.
|
||||
#[inline]
|
||||
pub(crate) fn is_empty(&self) -> bool {
|
||||
Instant::now() < self.delivery_time.load()
|
||||
}
|
||||
|
||||
/// Returns `true` if the channel is full.
|
||||
#[inline]
|
||||
pub(crate) fn is_full(&self) -> bool {
|
||||
!self.is_empty()
|
||||
}
|
||||
|
||||
/// Returns the number of messages in the channel.
|
||||
#[inline]
|
||||
pub(crate) fn len(&self) -> usize {
|
||||
if self.is_empty() {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the capacity of the channel.
|
||||
#[inline]
|
||||
pub(crate) fn capacity(&self) -> Option<usize> {
|
||||
Some(1)
|
||||
}
|
||||
}
|
||||
|
||||
impl SelectHandle for Channel {
|
||||
#[inline]
|
||||
fn try_select(&self, token: &mut Token) -> bool {
|
||||
match self.try_recv() {
|
||||
Ok(msg) => {
|
||||
token.tick = Some(msg);
|
||||
true
|
||||
}
|
||||
Err(TryRecvError::Disconnected) => {
|
||||
token.tick = None;
|
||||
true
|
||||
}
|
||||
Err(TryRecvError::Empty) => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn deadline(&self) -> Option<Instant> {
|
||||
Some(self.delivery_time.load())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn register(&self, _oper: Operation, _cx: &Context) -> bool {
|
||||
self.is_ready()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn unregister(&self, _oper: Operation) {}
|
||||
|
||||
#[inline]
|
||||
fn accept(&self, token: &mut Token, _cx: &Context) -> bool {
|
||||
self.try_select(token)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_ready(&self) -> bool {
|
||||
!self.is_empty()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn watch(&self, _oper: Operation, _cx: &Context) -> bool {
|
||||
self.is_ready()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn unwatch(&self, _oper: Operation) {}
|
||||
}
|
||||
496
third-party/vendor/crossbeam-channel/src/flavors/zero.rs
vendored
Normal file
496
third-party/vendor/crossbeam-channel/src/flavors/zero.rs
vendored
Normal file
|
|
@ -0,0 +1,496 @@
|
|||
//! Zero-capacity channel.
|
||||
//!
|
||||
//! This kind of channel is also known as *rendezvous* channel.
|
||||
|
||||
use std::boxed::Box;
|
||||
use std::cell::UnsafeCell;
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Mutex;
|
||||
use std::time::Instant;
|
||||
use std::{fmt, ptr};
|
||||
|
||||
use crossbeam_utils::Backoff;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::err::{RecvTimeoutError, SendTimeoutError, TryRecvError, TrySendError};
|
||||
use crate::select::{Operation, SelectHandle, Selected, Token};
|
||||
use crate::waker::Waker;
|
||||
|
||||
/// A pointer to a packet.
|
||||
pub(crate) struct ZeroToken(*mut ());
|
||||
|
||||
impl Default for ZeroToken {
|
||||
fn default() -> Self {
|
||||
Self(ptr::null_mut())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ZeroToken {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&(self.0 as usize), f)
|
||||
}
|
||||
}
|
||||
|
||||
/// A slot for passing one message from a sender to a receiver.
|
||||
struct Packet<T> {
|
||||
/// Equals `true` if the packet is allocated on the stack.
|
||||
on_stack: bool,
|
||||
|
||||
/// Equals `true` once the packet is ready for reading or writing.
|
||||
ready: AtomicBool,
|
||||
|
||||
/// The message.
|
||||
msg: UnsafeCell<Option<T>>,
|
||||
}
|
||||
|
||||
impl<T> Packet<T> {
|
||||
/// Creates an empty packet on the stack.
|
||||
fn empty_on_stack() -> Packet<T> {
|
||||
Packet {
|
||||
on_stack: true,
|
||||
ready: AtomicBool::new(false),
|
||||
msg: UnsafeCell::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an empty packet on the heap.
|
||||
fn empty_on_heap() -> Box<Packet<T>> {
|
||||
Box::new(Packet {
|
||||
on_stack: false,
|
||||
ready: AtomicBool::new(false),
|
||||
msg: UnsafeCell::new(None),
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates a packet on the stack, containing a message.
|
||||
fn message_on_stack(msg: T) -> Packet<T> {
|
||||
Packet {
|
||||
on_stack: true,
|
||||
ready: AtomicBool::new(false),
|
||||
msg: UnsafeCell::new(Some(msg)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Waits until the packet becomes ready for reading or writing.
|
||||
fn wait_ready(&self) {
|
||||
let backoff = Backoff::new();
|
||||
while !self.ready.load(Ordering::Acquire) {
|
||||
backoff.snooze();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Inner representation of a zero-capacity channel.
|
||||
struct Inner {
|
||||
/// Senders waiting to pair up with a receive operation.
|
||||
senders: Waker,
|
||||
|
||||
/// Receivers waiting to pair up with a send operation.
|
||||
receivers: Waker,
|
||||
|
||||
/// Equals `true` when the channel is disconnected.
|
||||
is_disconnected: bool,
|
||||
}
|
||||
|
||||
/// Zero-capacity channel.
|
||||
pub(crate) struct Channel<T> {
|
||||
/// Inner representation of the channel.
|
||||
inner: Mutex<Inner>,
|
||||
|
||||
/// Indicates that dropping a `Channel<T>` may drop values of type `T`.
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> Channel<T> {
|
||||
/// Constructs a new zero-capacity channel.
|
||||
pub(crate) fn new() -> Self {
|
||||
Channel {
|
||||
inner: Mutex::new(Inner {
|
||||
senders: Waker::new(),
|
||||
receivers: Waker::new(),
|
||||
is_disconnected: false,
|
||||
}),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a receiver handle to the channel.
|
||||
pub(crate) fn receiver(&self) -> Receiver<'_, T> {
|
||||
Receiver(self)
|
||||
}
|
||||
|
||||
/// Returns a sender handle to the channel.
|
||||
pub(crate) fn sender(&self) -> Sender<'_, T> {
|
||||
Sender(self)
|
||||
}
|
||||
|
||||
/// Attempts to reserve a slot for sending a message.
|
||||
fn start_send(&self, token: &mut Token) -> bool {
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
|
||||
// If there's a waiting receiver, pair up with it.
|
||||
if let Some(operation) = inner.receivers.try_select() {
|
||||
token.zero.0 = operation.packet;
|
||||
true
|
||||
} else if inner.is_disconnected {
|
||||
token.zero.0 = ptr::null_mut();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a message into the packet.
|
||||
pub(crate) unsafe fn write(&self, token: &mut Token, msg: T) -> Result<(), T> {
|
||||
// If there is no packet, the channel is disconnected.
|
||||
if token.zero.0.is_null() {
|
||||
return Err(msg);
|
||||
}
|
||||
|
||||
let packet = &*(token.zero.0 as *const Packet<T>);
|
||||
packet.msg.get().write(Some(msg));
|
||||
packet.ready.store(true, Ordering::Release);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Attempts to pair up with a sender.
|
||||
fn start_recv(&self, token: &mut Token) -> bool {
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
|
||||
// If there's a waiting sender, pair up with it.
|
||||
if let Some(operation) = inner.senders.try_select() {
|
||||
token.zero.0 = operation.packet;
|
||||
true
|
||||
} else if inner.is_disconnected {
|
||||
token.zero.0 = ptr::null_mut();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads a message from the packet.
|
||||
pub(crate) unsafe fn read(&self, token: &mut Token) -> Result<T, ()> {
|
||||
// If there is no packet, the channel is disconnected.
|
||||
if token.zero.0.is_null() {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let packet = &*(token.zero.0 as *const Packet<T>);
|
||||
|
||||
if packet.on_stack {
|
||||
// The message has been in the packet from the beginning, so there is no need to wait
|
||||
// for it. However, after reading the message, we need to set `ready` to `true` in
|
||||
// order to signal that the packet can be destroyed.
|
||||
let msg = packet.msg.get().replace(None).unwrap();
|
||||
packet.ready.store(true, Ordering::Release);
|
||||
Ok(msg)
|
||||
} else {
|
||||
// Wait until the message becomes available, then read it and destroy the
|
||||
// heap-allocated packet.
|
||||
packet.wait_ready();
|
||||
let msg = packet.msg.get().replace(None).unwrap();
|
||||
drop(Box::from_raw(token.zero.0.cast::<Packet<T>>()));
|
||||
Ok(msg)
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to send a message into the channel.
|
||||
pub(crate) fn try_send(&self, msg: T) -> Result<(), TrySendError<T>> {
|
||||
let token = &mut Token::default();
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
|
||||
// If there's a waiting receiver, pair up with it.
|
||||
if let Some(operation) = inner.receivers.try_select() {
|
||||
token.zero.0 = operation.packet;
|
||||
drop(inner);
|
||||
unsafe {
|
||||
self.write(token, msg).ok().unwrap();
|
||||
}
|
||||
Ok(())
|
||||
} else if inner.is_disconnected {
|
||||
Err(TrySendError::Disconnected(msg))
|
||||
} else {
|
||||
Err(TrySendError::Full(msg))
|
||||
}
|
||||
}
|
||||
|
||||
/// Sends a message into the channel.
|
||||
pub(crate) fn send(
|
||||
&self,
|
||||
msg: T,
|
||||
deadline: Option<Instant>,
|
||||
) -> Result<(), SendTimeoutError<T>> {
|
||||
let token = &mut Token::default();
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
|
||||
// If there's a waiting receiver, pair up with it.
|
||||
if let Some(operation) = inner.receivers.try_select() {
|
||||
token.zero.0 = operation.packet;
|
||||
drop(inner);
|
||||
unsafe {
|
||||
self.write(token, msg).ok().unwrap();
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if inner.is_disconnected {
|
||||
return Err(SendTimeoutError::Disconnected(msg));
|
||||
}
|
||||
|
||||
Context::with(|cx| {
|
||||
// Prepare for blocking until a receiver wakes us up.
|
||||
let oper = Operation::hook(token);
|
||||
let mut packet = Packet::<T>::message_on_stack(msg);
|
||||
inner
|
||||
.senders
|
||||
.register_with_packet(oper, &mut packet as *mut Packet<T> as *mut (), cx);
|
||||
inner.receivers.notify();
|
||||
drop(inner);
|
||||
|
||||
// Block the current thread.
|
||||
let sel = cx.wait_until(deadline);
|
||||
|
||||
match sel {
|
||||
Selected::Waiting => unreachable!(),
|
||||
Selected::Aborted => {
|
||||
self.inner.lock().unwrap().senders.unregister(oper).unwrap();
|
||||
let msg = unsafe { packet.msg.get().replace(None).unwrap() };
|
||||
Err(SendTimeoutError::Timeout(msg))
|
||||
}
|
||||
Selected::Disconnected => {
|
||||
self.inner.lock().unwrap().senders.unregister(oper).unwrap();
|
||||
let msg = unsafe { packet.msg.get().replace(None).unwrap() };
|
||||
Err(SendTimeoutError::Disconnected(msg))
|
||||
}
|
||||
Selected::Operation(_) => {
|
||||
// Wait until the message is read, then drop the packet.
|
||||
packet.wait_ready();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Attempts to receive a message without blocking.
|
||||
pub(crate) fn try_recv(&self) -> Result<T, TryRecvError> {
|
||||
let token = &mut Token::default();
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
|
||||
// If there's a waiting sender, pair up with it.
|
||||
if let Some(operation) = inner.senders.try_select() {
|
||||
token.zero.0 = operation.packet;
|
||||
drop(inner);
|
||||
unsafe { self.read(token).map_err(|_| TryRecvError::Disconnected) }
|
||||
} else if inner.is_disconnected {
|
||||
Err(TryRecvError::Disconnected)
|
||||
} else {
|
||||
Err(TryRecvError::Empty)
|
||||
}
|
||||
}
|
||||
|
||||
/// Receives a message from the channel.
|
||||
pub(crate) fn recv(&self, deadline: Option<Instant>) -> Result<T, RecvTimeoutError> {
|
||||
let token = &mut Token::default();
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
|
||||
// If there's a waiting sender, pair up with it.
|
||||
if let Some(operation) = inner.senders.try_select() {
|
||||
token.zero.0 = operation.packet;
|
||||
drop(inner);
|
||||
unsafe {
|
||||
return self.read(token).map_err(|_| RecvTimeoutError::Disconnected);
|
||||
}
|
||||
}
|
||||
|
||||
if inner.is_disconnected {
|
||||
return Err(RecvTimeoutError::Disconnected);
|
||||
}
|
||||
|
||||
Context::with(|cx| {
|
||||
// Prepare for blocking until a sender wakes us up.
|
||||
let oper = Operation::hook(token);
|
||||
let mut packet = Packet::<T>::empty_on_stack();
|
||||
inner.receivers.register_with_packet(
|
||||
oper,
|
||||
&mut packet as *mut Packet<T> as *mut (),
|
||||
cx,
|
||||
);
|
||||
inner.senders.notify();
|
||||
drop(inner);
|
||||
|
||||
// Block the current thread.
|
||||
let sel = cx.wait_until(deadline);
|
||||
|
||||
match sel {
|
||||
Selected::Waiting => unreachable!(),
|
||||
Selected::Aborted => {
|
||||
self.inner
|
||||
.lock()
|
||||
.unwrap()
|
||||
.receivers
|
||||
.unregister(oper)
|
||||
.unwrap();
|
||||
Err(RecvTimeoutError::Timeout)
|
||||
}
|
||||
Selected::Disconnected => {
|
||||
self.inner
|
||||
.lock()
|
||||
.unwrap()
|
||||
.receivers
|
||||
.unregister(oper)
|
||||
.unwrap();
|
||||
Err(RecvTimeoutError::Disconnected)
|
||||
}
|
||||
Selected::Operation(_) => {
|
||||
// Wait until the message is provided, then read it.
|
||||
packet.wait_ready();
|
||||
unsafe { Ok(packet.msg.get().replace(None).unwrap()) }
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Disconnects the channel and wakes up all blocked senders and receivers.
|
||||
///
|
||||
/// Returns `true` if this call disconnected the channel.
|
||||
pub(crate) fn disconnect(&self) -> bool {
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
|
||||
if !inner.is_disconnected {
|
||||
inner.is_disconnected = true;
|
||||
inner.senders.disconnect();
|
||||
inner.receivers.disconnect();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the current number of messages inside the channel.
|
||||
pub(crate) fn len(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
/// Returns the capacity of the channel.
|
||||
pub(crate) fn capacity(&self) -> Option<usize> {
|
||||
Some(0)
|
||||
}
|
||||
|
||||
/// Returns `true` if the channel is empty.
|
||||
pub(crate) fn is_empty(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Returns `true` if the channel is full.
|
||||
pub(crate) fn is_full(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// Receiver handle to a channel.
|
||||
pub(crate) struct Receiver<'a, T>(&'a Channel<T>);
|
||||
|
||||
/// Sender handle to a channel.
|
||||
pub(crate) struct Sender<'a, T>(&'a Channel<T>);
|
||||
|
||||
impl<T> SelectHandle for Receiver<'_, T> {
|
||||
fn try_select(&self, token: &mut Token) -> bool {
|
||||
self.0.start_recv(token)
|
||||
}
|
||||
|
||||
fn deadline(&self) -> Option<Instant> {
|
||||
None
|
||||
}
|
||||
|
||||
fn register(&self, oper: Operation, cx: &Context) -> bool {
|
||||
let packet = Box::into_raw(Packet::<T>::empty_on_heap());
|
||||
|
||||
let mut inner = self.0.inner.lock().unwrap();
|
||||
inner
|
||||
.receivers
|
||||
.register_with_packet(oper, packet.cast::<()>(), cx);
|
||||
inner.senders.notify();
|
||||
inner.senders.can_select() || inner.is_disconnected
|
||||
}
|
||||
|
||||
fn unregister(&self, oper: Operation) {
|
||||
if let Some(operation) = self.0.inner.lock().unwrap().receivers.unregister(oper) {
|
||||
unsafe {
|
||||
drop(Box::from_raw(operation.packet.cast::<Packet<T>>()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn accept(&self, token: &mut Token, cx: &Context) -> bool {
|
||||
token.zero.0 = cx.wait_packet();
|
||||
true
|
||||
}
|
||||
|
||||
fn is_ready(&self) -> bool {
|
||||
let inner = self.0.inner.lock().unwrap();
|
||||
inner.senders.can_select() || inner.is_disconnected
|
||||
}
|
||||
|
||||
fn watch(&self, oper: Operation, cx: &Context) -> bool {
|
||||
let mut inner = self.0.inner.lock().unwrap();
|
||||
inner.receivers.watch(oper, cx);
|
||||
inner.senders.can_select() || inner.is_disconnected
|
||||
}
|
||||
|
||||
fn unwatch(&self, oper: Operation) {
|
||||
let mut inner = self.0.inner.lock().unwrap();
|
||||
inner.receivers.unwatch(oper);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SelectHandle for Sender<'_, T> {
|
||||
fn try_select(&self, token: &mut Token) -> bool {
|
||||
self.0.start_send(token)
|
||||
}
|
||||
|
||||
fn deadline(&self) -> Option<Instant> {
|
||||
None
|
||||
}
|
||||
|
||||
fn register(&self, oper: Operation, cx: &Context) -> bool {
|
||||
let packet = Box::into_raw(Packet::<T>::empty_on_heap());
|
||||
|
||||
let mut inner = self.0.inner.lock().unwrap();
|
||||
inner
|
||||
.senders
|
||||
.register_with_packet(oper, packet.cast::<()>(), cx);
|
||||
inner.receivers.notify();
|
||||
inner.receivers.can_select() || inner.is_disconnected
|
||||
}
|
||||
|
||||
fn unregister(&self, oper: Operation) {
|
||||
if let Some(operation) = self.0.inner.lock().unwrap().senders.unregister(oper) {
|
||||
unsafe {
|
||||
drop(Box::from_raw(operation.packet.cast::<Packet<T>>()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn accept(&self, token: &mut Token, cx: &Context) -> bool {
|
||||
token.zero.0 = cx.wait_packet();
|
||||
true
|
||||
}
|
||||
|
||||
fn is_ready(&self) -> bool {
|
||||
let inner = self.0.inner.lock().unwrap();
|
||||
inner.receivers.can_select() || inner.is_disconnected
|
||||
}
|
||||
|
||||
fn watch(&self, oper: Operation, cx: &Context) -> bool {
|
||||
let mut inner = self.0.inner.lock().unwrap();
|
||||
inner.senders.watch(oper, cx);
|
||||
inner.receivers.can_select() || inner.is_disconnected
|
||||
}
|
||||
|
||||
fn unwatch(&self, oper: Operation) {
|
||||
let mut inner = self.0.inner.lock().unwrap();
|
||||
inner.senders.unwatch(oper);
|
||||
}
|
||||
}
|
||||
378
third-party/vendor/crossbeam-channel/src/lib.rs
vendored
Normal file
378
third-party/vendor/crossbeam-channel/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,378 @@
|
|||
//! Multi-producer multi-consumer channels for message passing.
|
||||
//!
|
||||
//! This crate is an alternative to [`std::sync::mpsc`] with more features and better performance.
|
||||
//!
|
||||
//! # Hello, world!
|
||||
//!
|
||||
//! ```
|
||||
//! use crossbeam_channel::unbounded;
|
||||
//!
|
||||
//! // Create a channel of unbounded capacity.
|
||||
//! let (s, r) = unbounded();
|
||||
//!
|
||||
//! // Send a message into the channel.
|
||||
//! s.send("Hello, world!").unwrap();
|
||||
//!
|
||||
//! // Receive the message from the channel.
|
||||
//! assert_eq!(r.recv(), Ok("Hello, world!"));
|
||||
//! ```
|
||||
//!
|
||||
//! # Channel types
|
||||
//!
|
||||
//! Channels can be created using two functions:
|
||||
//!
|
||||
//! * [`bounded`] creates a channel of bounded capacity, i.e. there is a limit to how many messages
|
||||
//! it can hold at a time.
|
||||
//!
|
||||
//! * [`unbounded`] creates a channel of unbounded capacity, i.e. it can hold any number of
|
||||
//! messages at a time.
|
||||
//!
|
||||
//! Both functions return a [`Sender`] and a [`Receiver`], which represent the two opposite sides
|
||||
//! of a channel.
|
||||
//!
|
||||
//! Creating a bounded channel:
|
||||
//!
|
||||
//! ```
|
||||
//! use crossbeam_channel::bounded;
|
||||
//!
|
||||
//! // Create a channel that can hold at most 5 messages at a time.
|
||||
//! let (s, r) = bounded(5);
|
||||
//!
|
||||
//! // Can send only 5 messages without blocking.
|
||||
//! for i in 0..5 {
|
||||
//! s.send(i).unwrap();
|
||||
//! }
|
||||
//!
|
||||
//! // Another call to `send` would block because the channel is full.
|
||||
//! // s.send(5).unwrap();
|
||||
//! ```
|
||||
//!
|
||||
//! Creating an unbounded channel:
|
||||
//!
|
||||
//! ```
|
||||
//! use crossbeam_channel::unbounded;
|
||||
//!
|
||||
//! // Create an unbounded channel.
|
||||
//! let (s, r) = unbounded();
|
||||
//!
|
||||
//! // Can send any number of messages into the channel without blocking.
|
||||
//! for i in 0..1000 {
|
||||
//! s.send(i).unwrap();
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! A special case is zero-capacity channel, which cannot hold any messages. Instead, send and
|
||||
//! receive operations must appear at the same time in order to pair up and pass the message over:
|
||||
//!
|
||||
//! ```
|
||||
//! use std::thread;
|
||||
//! use crossbeam_channel::bounded;
|
||||
//!
|
||||
//! // Create a zero-capacity channel.
|
||||
//! let (s, r) = bounded(0);
|
||||
//!
|
||||
//! // Sending blocks until a receive operation appears on the other side.
|
||||
//! thread::spawn(move || s.send("Hi!").unwrap());
|
||||
//!
|
||||
//! // Receiving blocks until a send operation appears on the other side.
|
||||
//! assert_eq!(r.recv(), Ok("Hi!"));
|
||||
//! ```
|
||||
//!
|
||||
//! # Sharing channels
|
||||
//!
|
||||
//! Senders and receivers can be cloned and sent to other threads:
|
||||
//!
|
||||
//! ```
|
||||
//! use std::thread;
|
||||
//! use crossbeam_channel::bounded;
|
||||
//!
|
||||
//! let (s1, r1) = bounded(0);
|
||||
//! let (s2, r2) = (s1.clone(), r1.clone());
|
||||
//!
|
||||
//! // Spawn a thread that receives a message and then sends one.
|
||||
//! thread::spawn(move || {
|
||||
//! r2.recv().unwrap();
|
||||
//! s2.send(2).unwrap();
|
||||
//! });
|
||||
//!
|
||||
//! // Send a message and then receive one.
|
||||
//! s1.send(1).unwrap();
|
||||
//! r1.recv().unwrap();
|
||||
//! ```
|
||||
//!
|
||||
//! Note that cloning only creates a new handle to the same sending or receiving side. It does not
|
||||
//! create a separate stream of messages in any way:
|
||||
//!
|
||||
//! ```
|
||||
//! use crossbeam_channel::unbounded;
|
||||
//!
|
||||
//! let (s1, r1) = unbounded();
|
||||
//! let (s2, r2) = (s1.clone(), r1.clone());
|
||||
//! let (s3, r3) = (s2.clone(), r2.clone());
|
||||
//!
|
||||
//! s1.send(10).unwrap();
|
||||
//! s2.send(20).unwrap();
|
||||
//! s3.send(30).unwrap();
|
||||
//!
|
||||
//! assert_eq!(r3.recv(), Ok(10));
|
||||
//! assert_eq!(r1.recv(), Ok(20));
|
||||
//! assert_eq!(r2.recv(), Ok(30));
|
||||
//! ```
|
||||
//!
|
||||
//! It's also possible to share senders and receivers by reference:
|
||||
//!
|
||||
//! ```
|
||||
//! use crossbeam_channel::bounded;
|
||||
//! use crossbeam_utils::thread::scope;
|
||||
//!
|
||||
//! let (s, r) = bounded(0);
|
||||
//!
|
||||
//! scope(|scope| {
|
||||
//! // Spawn a thread that receives a message and then sends one.
|
||||
//! scope.spawn(|_| {
|
||||
//! r.recv().unwrap();
|
||||
//! s.send(2).unwrap();
|
||||
//! });
|
||||
//!
|
||||
//! // Send a message and then receive one.
|
||||
//! s.send(1).unwrap();
|
||||
//! r.recv().unwrap();
|
||||
//! }).unwrap();
|
||||
//! ```
|
||||
//!
|
||||
//! # Disconnection
|
||||
//!
|
||||
//! When all senders or all receivers associated with a channel get dropped, the channel becomes
|
||||
//! disconnected. No more messages can be sent, but any remaining messages can still be received.
|
||||
//! Send and receive operations on a disconnected channel never block.
|
||||
//!
|
||||
//! ```
|
||||
//! use crossbeam_channel::{unbounded, RecvError};
|
||||
//!
|
||||
//! let (s, r) = unbounded();
|
||||
//! s.send(1).unwrap();
|
||||
//! s.send(2).unwrap();
|
||||
//! s.send(3).unwrap();
|
||||
//!
|
||||
//! // The only sender is dropped, disconnecting the channel.
|
||||
//! drop(s);
|
||||
//!
|
||||
//! // The remaining messages can be received.
|
||||
//! assert_eq!(r.recv(), Ok(1));
|
||||
//! assert_eq!(r.recv(), Ok(2));
|
||||
//! assert_eq!(r.recv(), Ok(3));
|
||||
//!
|
||||
//! // There are no more messages in the channel.
|
||||
//! assert!(r.is_empty());
|
||||
//!
|
||||
//! // Note that calling `r.recv()` does not block.
|
||||
//! // Instead, `Err(RecvError)` is returned immediately.
|
||||
//! assert_eq!(r.recv(), Err(RecvError));
|
||||
//! ```
|
||||
//!
|
||||
//! # Blocking operations
|
||||
//!
|
||||
//! Send and receive operations come in three flavors:
|
||||
//!
|
||||
//! * Non-blocking (returns immediately with success or failure).
|
||||
//! * Blocking (waits until the operation succeeds or the channel becomes disconnected).
|
||||
//! * Blocking with a timeout (blocks only for a certain duration of time).
|
||||
//!
|
||||
//! A simple example showing the difference between non-blocking and blocking operations:
|
||||
//!
|
||||
//! ```
|
||||
//! use crossbeam_channel::{bounded, RecvError, TryRecvError};
|
||||
//!
|
||||
//! let (s, r) = bounded(1);
|
||||
//!
|
||||
//! // Send a message into the channel.
|
||||
//! s.send("foo").unwrap();
|
||||
//!
|
||||
//! // This call would block because the channel is full.
|
||||
//! // s.send("bar").unwrap();
|
||||
//!
|
||||
//! // Receive the message.
|
||||
//! assert_eq!(r.recv(), Ok("foo"));
|
||||
//!
|
||||
//! // This call would block because the channel is empty.
|
||||
//! // r.recv();
|
||||
//!
|
||||
//! // Try receiving a message without blocking.
|
||||
//! assert_eq!(r.try_recv(), Err(TryRecvError::Empty));
|
||||
//!
|
||||
//! // Disconnect the channel.
|
||||
//! drop(s);
|
||||
//!
|
||||
//! // This call doesn't block because the channel is now disconnected.
|
||||
//! assert_eq!(r.recv(), Err(RecvError));
|
||||
//! ```
|
||||
//!
|
||||
//! # Iteration
|
||||
//!
|
||||
//! Receivers can be used as iterators. For example, method [`iter`] creates an iterator that
|
||||
//! receives messages until the channel becomes empty and disconnected. Note that iteration may
|
||||
//! block waiting for next message to arrive.
|
||||
//!
|
||||
//! ```
|
||||
//! use std::thread;
|
||||
//! use crossbeam_channel::unbounded;
|
||||
//!
|
||||
//! let (s, r) = unbounded();
|
||||
//!
|
||||
//! thread::spawn(move || {
|
||||
//! s.send(1).unwrap();
|
||||
//! s.send(2).unwrap();
|
||||
//! s.send(3).unwrap();
|
||||
//! drop(s); // Disconnect the channel.
|
||||
//! });
|
||||
//!
|
||||
//! // Collect all messages from the channel.
|
||||
//! // Note that the call to `collect` blocks until the sender is dropped.
|
||||
//! let v: Vec<_> = r.iter().collect();
|
||||
//!
|
||||
//! assert_eq!(v, [1, 2, 3]);
|
||||
//! ```
|
||||
//!
|
||||
//! A non-blocking iterator can be created using [`try_iter`], which receives all available
|
||||
//! messages without blocking:
|
||||
//!
|
||||
//! ```
|
||||
//! use crossbeam_channel::unbounded;
|
||||
//!
|
||||
//! let (s, r) = unbounded();
|
||||
//! s.send(1).unwrap();
|
||||
//! s.send(2).unwrap();
|
||||
//! s.send(3).unwrap();
|
||||
//! // No need to drop the sender.
|
||||
//!
|
||||
//! // Receive all messages currently in the channel.
|
||||
//! let v: Vec<_> = r.try_iter().collect();
|
||||
//!
|
||||
//! assert_eq!(v, [1, 2, 3]);
|
||||
//! ```
|
||||
//!
|
||||
//! # Selection
|
||||
//!
|
||||
//! The [`select!`] macro allows you to define a set of channel operations, wait until any one of
|
||||
//! them becomes ready, and finally execute it. If multiple operations are ready at the same time,
|
||||
//! a random one among them is selected.
|
||||
//!
|
||||
//! It is also possible to define a `default` case that gets executed if none of the operations are
|
||||
//! ready, either right away or for a certain duration of time.
|
||||
//!
|
||||
//! An operation is considered to be ready if it doesn't have to block. Note that it is ready even
|
||||
//! when it will simply return an error because the channel is disconnected.
|
||||
//!
|
||||
//! An example of receiving a message from two channels:
|
||||
//!
|
||||
//! ```
|
||||
//! use std::thread;
|
||||
//! use std::time::Duration;
|
||||
//! use crossbeam_channel::{select, unbounded};
|
||||
//!
|
||||
//! let (s1, r1) = unbounded();
|
||||
//! let (s2, r2) = unbounded();
|
||||
//!
|
||||
//! thread::spawn(move || s1.send(10).unwrap());
|
||||
//! thread::spawn(move || s2.send(20).unwrap());
|
||||
//!
|
||||
//! // At most one of these two receive operations will be executed.
|
||||
//! select! {
|
||||
//! recv(r1) -> msg => assert_eq!(msg, Ok(10)),
|
||||
//! recv(r2) -> msg => assert_eq!(msg, Ok(20)),
|
||||
//! default(Duration::from_secs(1)) => println!("timed out"),
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! If you need to select over a dynamically created list of channel operations, use [`Select`]
|
||||
//! instead. The [`select!`] macro is just a convenience wrapper around [`Select`].
|
||||
//!
|
||||
//! # Extra channels
|
||||
//!
|
||||
//! Three functions can create special kinds of channels, all of which return just a [`Receiver`]
|
||||
//! handle:
|
||||
//!
|
||||
//! * [`after`] creates a channel that delivers a single message after a certain duration of time.
|
||||
//! * [`tick`] creates a channel that delivers messages periodically.
|
||||
//! * [`never`](never()) creates a channel that never delivers messages.
|
||||
//!
|
||||
//! These channels are very efficient because messages get lazily generated on receive operations.
|
||||
//!
|
||||
//! An example that prints elapsed time every 50 milliseconds for the duration of 1 second:
|
||||
//!
|
||||
//! ```
|
||||
//! use std::time::{Duration, Instant};
|
||||
//! use crossbeam_channel::{after, select, tick};
|
||||
//!
|
||||
//! let start = Instant::now();
|
||||
//! let ticker = tick(Duration::from_millis(50));
|
||||
//! let timeout = after(Duration::from_secs(1));
|
||||
//!
|
||||
//! loop {
|
||||
//! select! {
|
||||
//! recv(ticker) -> _ => println!("elapsed: {:?}", start.elapsed()),
|
||||
//! recv(timeout) -> _ => break,
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! [`send`]: Sender::send
|
||||
//! [`recv`]: Receiver::recv
|
||||
//! [`iter`]: Receiver::iter
|
||||
//! [`try_iter`]: Receiver::try_iter
|
||||
|
||||
#![no_std]
|
||||
#![doc(test(
|
||||
no_crate_inject,
|
||||
attr(
|
||||
deny(warnings, rust_2018_idioms),
|
||||
allow(dead_code, unused_assignments, unused_variables)
|
||||
)
|
||||
))]
|
||||
#![warn(
|
||||
missing_docs,
|
||||
missing_debug_implementations,
|
||||
rust_2018_idioms,
|
||||
unreachable_pub
|
||||
)]
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
extern crate std;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
mod channel;
|
||||
#[cfg(feature = "std")]
|
||||
mod context;
|
||||
#[cfg(feature = "std")]
|
||||
mod counter;
|
||||
#[cfg(feature = "std")]
|
||||
mod err;
|
||||
#[cfg(feature = "std")]
|
||||
mod flavors;
|
||||
#[cfg(feature = "std")]
|
||||
mod select;
|
||||
#[cfg(feature = "std")]
|
||||
mod select_macro;
|
||||
#[cfg(feature = "std")]
|
||||
mod utils;
|
||||
#[cfg(feature = "std")]
|
||||
mod waker;
|
||||
|
||||
/// Crate internals used by the `select!` macro.
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "std")]
|
||||
pub mod internal {
|
||||
pub use crate::select::{select, select_timeout, try_select, SelectHandle};
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use crate::{
|
||||
channel::{
|
||||
after, at, bounded, never, tick, unbounded, IntoIter, Iter, Receiver, Sender, TryIter,
|
||||
},
|
||||
err::{
|
||||
ReadyTimeoutError, RecvError, RecvTimeoutError, SelectTimeoutError, SendError,
|
||||
SendTimeoutError, TryReadyError, TryRecvError, TrySelectError, TrySendError,
|
||||
},
|
||||
select::{Select, SelectedOperation},
|
||||
};
|
||||
1263
third-party/vendor/crossbeam-channel/src/select.rs
vendored
Normal file
1263
third-party/vendor/crossbeam-channel/src/select.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
1116
third-party/vendor/crossbeam-channel/src/select_macro.rs
vendored
Normal file
1116
third-party/vendor/crossbeam-channel/src/select_macro.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
58
third-party/vendor/crossbeam-channel/src/utils.rs
vendored
Normal file
58
third-party/vendor/crossbeam-channel/src/utils.rs
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
//! Miscellaneous utilities.
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::num::Wrapping;
|
||||
use std::thread;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
/// Randomly shuffles a slice.
|
||||
pub(crate) fn shuffle<T>(v: &mut [T]) {
|
||||
let len = v.len();
|
||||
if len <= 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
std::thread_local! {
|
||||
static RNG: Cell<Wrapping<u32>> = const { Cell::new(Wrapping(1_406_868_647)) };
|
||||
}
|
||||
|
||||
let _ = RNG.try_with(|rng| {
|
||||
for i in 1..len {
|
||||
// This is the 32-bit variant of Xorshift.
|
||||
//
|
||||
// Source: https://en.wikipedia.org/wiki/Xorshift
|
||||
let mut x = rng.get();
|
||||
x ^= x << 13;
|
||||
x ^= x >> 17;
|
||||
x ^= x << 5;
|
||||
rng.set(x);
|
||||
|
||||
let x = x.0;
|
||||
let n = i + 1;
|
||||
|
||||
// This is a fast alternative to `let j = x % n`.
|
||||
//
|
||||
// Author: Daniel Lemire
|
||||
// Source: https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
|
||||
let j = ((x as u64).wrapping_mul(n as u64) >> 32) as u32 as usize;
|
||||
|
||||
v.swap(i, j);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Sleeps until the deadline, or forever if the deadline isn't specified.
|
||||
pub(crate) fn sleep_until(deadline: Option<Instant>) {
|
||||
loop {
|
||||
match deadline {
|
||||
None => thread::sleep(Duration::from_secs(1000)),
|
||||
Some(d) => {
|
||||
let now = Instant::now();
|
||||
if now >= d {
|
||||
break;
|
||||
}
|
||||
thread::sleep(d - now);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
287
third-party/vendor/crossbeam-channel/src/waker.rs
vendored
Normal file
287
third-party/vendor/crossbeam-channel/src/waker.rs
vendored
Normal file
|
|
@ -0,0 +1,287 @@
|
|||
//! Waking mechanism for threads blocked on channel operations.
|
||||
|
||||
use std::ptr;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Mutex;
|
||||
use std::thread::{self, ThreadId};
|
||||
use std::vec::Vec;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::select::{Operation, Selected};
|
||||
|
||||
/// Represents a thread blocked on a specific channel operation.
|
||||
pub(crate) struct Entry {
|
||||
/// The operation.
|
||||
pub(crate) oper: Operation,
|
||||
|
||||
/// Optional packet.
|
||||
pub(crate) packet: *mut (),
|
||||
|
||||
/// Context associated with the thread owning this operation.
|
||||
pub(crate) cx: Context,
|
||||
}
|
||||
|
||||
/// A queue of threads blocked on channel operations.
|
||||
///
|
||||
/// This data structure is used by threads to register blocking operations and get woken up once
|
||||
/// an operation becomes ready.
|
||||
pub(crate) struct Waker {
|
||||
/// A list of select operations.
|
||||
selectors: Vec<Entry>,
|
||||
|
||||
/// A list of operations waiting to be ready.
|
||||
observers: Vec<Entry>,
|
||||
}
|
||||
|
||||
impl Waker {
|
||||
/// Creates a new `Waker`.
|
||||
#[inline]
|
||||
pub(crate) fn new() -> Self {
|
||||
Waker {
|
||||
selectors: Vec::new(),
|
||||
observers: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers a select operation.
|
||||
#[inline]
|
||||
pub(crate) fn register(&mut self, oper: Operation, cx: &Context) {
|
||||
self.register_with_packet(oper, ptr::null_mut(), cx);
|
||||
}
|
||||
|
||||
/// Registers a select operation and a packet.
|
||||
#[inline]
|
||||
pub(crate) fn register_with_packet(&mut self, oper: Operation, packet: *mut (), cx: &Context) {
|
||||
self.selectors.push(Entry {
|
||||
oper,
|
||||
packet,
|
||||
cx: cx.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
/// Unregisters a select operation.
|
||||
#[inline]
|
||||
pub(crate) fn unregister(&mut self, oper: Operation) -> Option<Entry> {
|
||||
if let Some((i, _)) = self
|
||||
.selectors
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|&(_, entry)| entry.oper == oper)
|
||||
{
|
||||
let entry = self.selectors.remove(i);
|
||||
Some(entry)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to find another thread's entry, select the operation, and wake it up.
|
||||
#[inline]
|
||||
pub(crate) fn try_select(&mut self) -> Option<Entry> {
|
||||
if self.selectors.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let thread_id = current_thread_id();
|
||||
|
||||
self.selectors
|
||||
.iter()
|
||||
.position(|selector| {
|
||||
// Does the entry belong to a different thread?
|
||||
selector.cx.thread_id() != thread_id
|
||||
&& selector // Try selecting this operation.
|
||||
.cx
|
||||
.try_select(Selected::Operation(selector.oper))
|
||||
.is_ok()
|
||||
&& {
|
||||
// Provide the packet.
|
||||
selector.cx.store_packet(selector.packet);
|
||||
// Wake the thread up.
|
||||
selector.cx.unpark();
|
||||
true
|
||||
}
|
||||
})
|
||||
// Remove the entry from the queue to keep it clean and improve
|
||||
// performance.
|
||||
.map(|pos| self.selectors.remove(pos))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if there is an entry which can be selected by the current thread.
|
||||
#[inline]
|
||||
pub(crate) fn can_select(&self) -> bool {
|
||||
if self.selectors.is_empty() {
|
||||
false
|
||||
} else {
|
||||
let thread_id = current_thread_id();
|
||||
|
||||
self.selectors.iter().any(|entry| {
|
||||
entry.cx.thread_id() != thread_id && entry.cx.selected() == Selected::Waiting
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers an operation waiting to be ready.
|
||||
#[inline]
|
||||
pub(crate) fn watch(&mut self, oper: Operation, cx: &Context) {
|
||||
self.observers.push(Entry {
|
||||
oper,
|
||||
packet: ptr::null_mut(),
|
||||
cx: cx.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
/// Unregisters an operation waiting to be ready.
|
||||
#[inline]
|
||||
pub(crate) fn unwatch(&mut self, oper: Operation) {
|
||||
self.observers.retain(|e| e.oper != oper);
|
||||
}
|
||||
|
||||
/// Notifies all operations waiting to be ready.
|
||||
#[inline]
|
||||
pub(crate) fn notify(&mut self) {
|
||||
for entry in self.observers.drain(..) {
|
||||
if entry.cx.try_select(Selected::Operation(entry.oper)).is_ok() {
|
||||
entry.cx.unpark();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Notifies all registered operations that the channel is disconnected.
|
||||
#[inline]
|
||||
pub(crate) fn disconnect(&mut self) {
|
||||
for entry in self.selectors.iter() {
|
||||
if entry.cx.try_select(Selected::Disconnected).is_ok() {
|
||||
// Wake the thread up.
|
||||
//
|
||||
// Here we don't remove the entry from the queue. Registered threads must
|
||||
// unregister from the waker by themselves. They might also want to recover the
|
||||
// packet value and destroy it, if necessary.
|
||||
entry.cx.unpark();
|
||||
}
|
||||
}
|
||||
|
||||
self.notify();
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Waker {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
debug_assert_eq!(self.selectors.len(), 0);
|
||||
debug_assert_eq!(self.observers.len(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// A waker that can be shared among threads without locking.
|
||||
///
|
||||
/// This is a simple wrapper around `Waker` that internally uses a mutex for synchronization.
|
||||
pub(crate) struct SyncWaker {
|
||||
/// The inner `Waker`.
|
||||
inner: Mutex<Waker>,
|
||||
|
||||
/// `true` if the waker is empty.
|
||||
is_empty: AtomicBool,
|
||||
}
|
||||
|
||||
impl SyncWaker {
|
||||
/// Creates a new `SyncWaker`.
|
||||
#[inline]
|
||||
pub(crate) fn new() -> Self {
|
||||
SyncWaker {
|
||||
inner: Mutex::new(Waker::new()),
|
||||
is_empty: AtomicBool::new(true),
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers the current thread with an operation.
|
||||
#[inline]
|
||||
pub(crate) fn register(&self, oper: Operation, cx: &Context) {
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
inner.register(oper, cx);
|
||||
self.is_empty.store(
|
||||
inner.selectors.is_empty() && inner.observers.is_empty(),
|
||||
Ordering::SeqCst,
|
||||
);
|
||||
}
|
||||
|
||||
/// Unregisters an operation previously registered by the current thread.
|
||||
#[inline]
|
||||
pub(crate) fn unregister(&self, oper: Operation) -> Option<Entry> {
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
let entry = inner.unregister(oper);
|
||||
self.is_empty.store(
|
||||
inner.selectors.is_empty() && inner.observers.is_empty(),
|
||||
Ordering::SeqCst,
|
||||
);
|
||||
entry
|
||||
}
|
||||
|
||||
/// Attempts to find one thread (not the current one), select its operation, and wake it up.
|
||||
#[inline]
|
||||
pub(crate) fn notify(&self) {
|
||||
if !self.is_empty.load(Ordering::SeqCst) {
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
if !self.is_empty.load(Ordering::SeqCst) {
|
||||
inner.try_select();
|
||||
inner.notify();
|
||||
self.is_empty.store(
|
||||
inner.selectors.is_empty() && inner.observers.is_empty(),
|
||||
Ordering::SeqCst,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers an operation waiting to be ready.
|
||||
#[inline]
|
||||
pub(crate) fn watch(&self, oper: Operation, cx: &Context) {
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
inner.watch(oper, cx);
|
||||
self.is_empty.store(
|
||||
inner.selectors.is_empty() && inner.observers.is_empty(),
|
||||
Ordering::SeqCst,
|
||||
);
|
||||
}
|
||||
|
||||
/// Unregisters an operation waiting to be ready.
|
||||
#[inline]
|
||||
pub(crate) fn unwatch(&self, oper: Operation) {
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
inner.unwatch(oper);
|
||||
self.is_empty.store(
|
||||
inner.selectors.is_empty() && inner.observers.is_empty(),
|
||||
Ordering::SeqCst,
|
||||
);
|
||||
}
|
||||
|
||||
/// Notifies all threads that the channel is disconnected.
|
||||
#[inline]
|
||||
pub(crate) fn disconnect(&self) {
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
inner.disconnect();
|
||||
self.is_empty.store(
|
||||
inner.selectors.is_empty() && inner.observers.is_empty(),
|
||||
Ordering::SeqCst,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SyncWaker {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
debug_assert!(self.is_empty.load(Ordering::SeqCst));
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the id of the current thread.
|
||||
#[inline]
|
||||
fn current_thread_id() -> ThreadId {
|
||||
std::thread_local! {
|
||||
/// Cached thread-local id.
|
||||
static THREAD_ID: ThreadId = thread::current().id();
|
||||
}
|
||||
|
||||
THREAD_ID
|
||||
.try_with(|id| *id)
|
||||
.unwrap_or_else(|_| thread::current().id())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue