Rename reactor -> driver, prep for lib/reactivity
This commit is contained in:
@@ -1,4 +1,14 @@
|
||||
//! Async channels for inter-thread communication.
|
||||
//!
|
||||
//! The channel types in this module are userspace synchronization primitives. They do not carry
|
||||
//! messages through the kernel; instead, channel state lives in shared Rust data structures and
|
||||
//! the runtime uses `io_uring` `MSG_RING` notifications only to wake the owning runtime thread
|
||||
//! when an async waiter becomes ready.
|
||||
//!
|
||||
//! The initial surface includes:
|
||||
//!
|
||||
//! - [`oneshot`] for single-value handoff
|
||||
//! - [`mpsc`] for bounded and unbounded multi-producer/single-consumer queues
|
||||
|
||||
pub mod mpsc;
|
||||
pub mod oneshot;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//! Multi-producer, single-consumer channels.
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::future::poll_fn;
|
||||
use std::pin::Pin;
|
||||
@@ -7,6 +9,13 @@ use std::task::{Context, Poll};
|
||||
use crate::op::completion::{CompletionFuture, CompletionHandle};
|
||||
use crate::sys::linux::channel::runtime_waiter;
|
||||
|
||||
/// Creates a bounded channel with room for at most `capacity` queued messages.
|
||||
///
|
||||
/// Bounded senders provide both [`Sender::try_send`] and async [`Sender::send`] backpressure.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `capacity == 0`.
|
||||
pub fn channel<T: Send + 'static>(capacity: usize) -> (Sender<T>, Receiver<T>) {
|
||||
assert!(capacity > 0, "bounded channels require capacity > 0");
|
||||
let shared = Arc::new(Mutex::new(State::new(Some(capacity))));
|
||||
@@ -18,6 +27,9 @@ pub fn channel<T: Send + 'static>(capacity: usize) -> (Sender<T>, Receiver<T>) {
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates an unbounded channel.
|
||||
///
|
||||
/// Unbounded senders never wait for capacity, but the single receiver is still asynchronous.
|
||||
pub fn unbounded_channel<T: Send + 'static>() -> (UnboundedSender<T>, Receiver<T>) {
|
||||
let shared = Arc::new(Mutex::new(State::new(None)));
|
||||
(
|
||||
@@ -28,14 +40,17 @@ pub fn unbounded_channel<T: Send + 'static>() -> (UnboundedSender<T>, Receiver<T
|
||||
)
|
||||
}
|
||||
|
||||
/// Bounded multi-producer sender.
|
||||
pub struct Sender<T: Send + 'static> {
|
||||
shared: Arc<Mutex<State<T>>>,
|
||||
}
|
||||
|
||||
/// Unbounded multi-producer sender.
|
||||
pub struct UnboundedSender<T: Send + 'static> {
|
||||
shared: Arc<Mutex<State<T>>>,
|
||||
}
|
||||
|
||||
/// Single consumer for both bounded and unbounded MPSC channels.
|
||||
pub struct Receiver<T: Send + 'static> {
|
||||
shared: Arc<Mutex<State<T>>>,
|
||||
}
|
||||
@@ -57,17 +72,24 @@ struct SendWaiter<T: Send + 'static> {
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
/// Error returned when sending fails because the receiver has been closed or dropped.
|
||||
pub struct SendError<T>(pub T);
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
/// Error returned by [`Sender::try_send`] when a message cannot be queued immediately.
|
||||
pub enum TrySendError<T> {
|
||||
/// The bounded queue is currently full.
|
||||
Full(T),
|
||||
/// The receiver has been closed or dropped.
|
||||
Closed(T),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
/// Error returned by [`Receiver::try_recv`] when no message is available immediately.
|
||||
pub enum TryRecvError {
|
||||
/// The channel is still open, but currently empty.
|
||||
Empty,
|
||||
/// The channel is closed and no more messages can arrive.
|
||||
Disconnected,
|
||||
}
|
||||
|
||||
@@ -215,12 +237,20 @@ impl<T: Send + 'static> Clone for UnboundedSender<T> {
|
||||
}
|
||||
|
||||
impl<T: Send + 'static> Sender<T> {
|
||||
/// Waits until the message can be queued.
|
||||
///
|
||||
/// When the bounded channel is full, this future waits until the receiver frees capacity.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if this future is first polled outside a runtime-managed thread.
|
||||
pub async fn send(&self, value: T) -> Result<(), SendError<T>> {
|
||||
let mut value = Some(value);
|
||||
let mut wait = None;
|
||||
poll_fn(|cx| self.poll_send(cx, &mut value, &mut wait)).await
|
||||
}
|
||||
|
||||
/// Attempts to queue a message immediately.
|
||||
pub fn try_send(&self, value: T) -> Result<(), TrySendError<T>> {
|
||||
self.shared
|
||||
.lock()
|
||||
@@ -228,6 +258,7 @@ impl<T: Send + 'static> Sender<T> {
|
||||
.try_send_now(value)
|
||||
}
|
||||
|
||||
/// Returns `true` if the receiver has been closed or dropped.
|
||||
pub fn is_closed(&self) -> bool {
|
||||
self.shared
|
||||
.lock()
|
||||
@@ -306,6 +337,7 @@ impl<T: Send + 'static> Sender<T> {
|
||||
}
|
||||
|
||||
impl<T: Send + 'static> UnboundedSender<T> {
|
||||
/// Queues a message immediately.
|
||||
pub fn send(&self, value: T) -> Result<(), SendError<T>> {
|
||||
self.shared
|
||||
.lock()
|
||||
@@ -316,6 +348,7 @@ impl<T: Send + 'static> UnboundedSender<T> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns `true` if the receiver has been closed or dropped.
|
||||
pub fn is_closed(&self) -> bool {
|
||||
self.shared
|
||||
.lock()
|
||||
@@ -325,11 +358,19 @@ impl<T: Send + 'static> UnboundedSender<T> {
|
||||
}
|
||||
|
||||
impl<T: Send + 'static> Receiver<T> {
|
||||
/// Waits for the next message.
|
||||
///
|
||||
/// Returns `None` when the channel is closed and all buffered messages have been drained.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if this future is first polled outside a runtime-managed thread.
|
||||
pub async fn recv(&mut self) -> Option<T> {
|
||||
let mut wait = None;
|
||||
poll_fn(|cx| self.poll_recv(cx, &mut wait)).await
|
||||
}
|
||||
|
||||
/// Attempts to receive a message immediately.
|
||||
pub fn try_recv(&mut self) -> Result<T, TryRecvError> {
|
||||
let mut state = self
|
||||
.shared
|
||||
@@ -345,6 +386,10 @@ impl<T: Send + 'static> Receiver<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Closes the channel to future sends.
|
||||
///
|
||||
/// Already-buffered messages remain available to [`recv`](Self::recv) and
|
||||
/// [`try_recv`](Self::try_recv).
|
||||
pub fn close(&mut self) {
|
||||
self.shared
|
||||
.lock()
|
||||
@@ -352,6 +397,7 @@ impl<T: Send + 'static> Receiver<T> {
|
||||
.close_receiver();
|
||||
}
|
||||
|
||||
/// Returns `true` if the channel is closed or all senders have been dropped.
|
||||
pub fn is_closed(&self) -> bool {
|
||||
let state = self
|
||||
.shared
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//! Single-use channels for handing one value from a sender to a receiver.
|
||||
|
||||
use std::future::poll_fn;
|
||||
use std::pin::Pin;
|
||||
use std::sync::{Arc, Mutex};
|
||||
@@ -6,6 +8,15 @@ use std::task::{Context, Poll};
|
||||
use crate::op::completion::{CompletionFuture, CompletionHandle};
|
||||
use crate::sys::linux::channel::runtime_waiter;
|
||||
|
||||
/// Creates a single-use channel for transferring one value from a [`Sender`] to a [`Receiver`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let (sender, mut receiver) = ruin_runtime::channel::oneshot::channel::<usize>();
|
||||
/// sender.send(7).unwrap();
|
||||
/// assert_eq!(receiver.try_recv(), Ok(7));
|
||||
/// ```
|
||||
pub fn channel<T: Send + 'static>() -> (Sender<T>, Receiver<T>) {
|
||||
let shared = Arc::new(Mutex::new(State {
|
||||
value: None,
|
||||
@@ -24,10 +35,12 @@ pub fn channel<T: Send + 'static>() -> (Sender<T>, Receiver<T>) {
|
||||
)
|
||||
}
|
||||
|
||||
/// Sending half of a oneshot channel.
|
||||
pub struct Sender<T: Send + 'static> {
|
||||
shared: Option<Arc<Mutex<State<T>>>>,
|
||||
}
|
||||
|
||||
/// Receiving half of a oneshot channel.
|
||||
pub struct Receiver<T: Send + 'static> {
|
||||
shared: Arc<Mutex<State<T>>>,
|
||||
consumed: bool,
|
||||
@@ -41,18 +54,27 @@ struct State<T: Send + 'static> {
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
/// Error returned when a oneshot send fails because the receiver is gone or closed.
|
||||
pub struct SendError<T>(pub T);
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
/// Error returned when a oneshot receive observes a closed channel with no value.
|
||||
pub struct RecvError;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
/// Non-blocking receive errors for [`Receiver::try_recv`].
|
||||
pub enum TryRecvError {
|
||||
/// No value has been sent yet, and the sender is still alive.
|
||||
Empty,
|
||||
/// The channel can never yield a value.
|
||||
Closed,
|
||||
}
|
||||
|
||||
impl<T: Send + 'static> Sender<T> {
|
||||
/// Sends `value` into the channel.
|
||||
///
|
||||
/// This consumes the sender. If the receiver is already waiting on a runtime thread, the
|
||||
/// receive future is woken through the runtime's cross-thread notifier path.
|
||||
pub fn send(mut self, value: T) -> Result<(), SendError<T>> {
|
||||
let Some(shared) = self.shared.take() else {
|
||||
return Err(SendError(value));
|
||||
@@ -80,6 +102,7 @@ impl<T: Send + 'static> Sender<T> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns `true` if the receiver has been closed or dropped.
|
||||
pub fn is_closed(&self) -> bool {
|
||||
self.shared.as_ref().is_none_or(|shared| {
|
||||
shared
|
||||
@@ -91,11 +114,19 @@ impl<T: Send + 'static> Sender<T> {
|
||||
}
|
||||
|
||||
impl<T: Send + 'static> Receiver<T> {
|
||||
/// Waits for the channel's value.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if this future is first polled outside a runtime-managed thread. Async channel
|
||||
/// waiting registers with the current runtime thread so it can be woken through the driver's
|
||||
/// notification path.
|
||||
pub async fn recv(&mut self) -> Result<T, RecvError> {
|
||||
let mut wait = None;
|
||||
poll_fn(|cx| self.poll_recv(cx, &mut wait)).await
|
||||
}
|
||||
|
||||
/// Attempts to receive the value without waiting.
|
||||
pub fn try_recv(&mut self) -> Result<T, TryRecvError> {
|
||||
if self.consumed {
|
||||
return Err(TryRecvError::Closed);
|
||||
@@ -118,6 +149,10 @@ impl<T: Send + 'static> Receiver<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Closes the receiver.
|
||||
///
|
||||
/// Closing prevents future sends from succeeding. If a value has already been sent, it can
|
||||
/// still be retrieved.
|
||||
pub fn close(&mut self) {
|
||||
let mut state = self
|
||||
.shared
|
||||
@@ -126,6 +161,7 @@ impl<T: Send + 'static> Receiver<T> {
|
||||
state.receiver_closed = true;
|
||||
}
|
||||
|
||||
/// Returns `true` if the channel is closed to future sends.
|
||||
pub fn is_closed(&self) -> bool {
|
||||
let state = self
|
||||
.shared
|
||||
|
||||
Reference in New Issue
Block a user