Rename reactor -> driver, prep for lib/reactivity
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
//! Public runtime driver primitives.
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::BTreeMap;
|
||||
@@ -51,23 +53,29 @@ impl NotifierInner {
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
/// Cross-thread notifier for a runtime thread's driver.
|
||||
pub struct ThreadNotifier {
|
||||
inner: Arc<NotifierInner>,
|
||||
}
|
||||
|
||||
impl ThreadNotifier {
|
||||
/// Sends a wake notification to the target runtime thread.
|
||||
pub fn notify(&self) -> io::Result<()> {
|
||||
self.inner.notify()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
|
||||
/// Readiness information returned by [`Driver::poll`].
|
||||
pub struct ReadyEvents {
|
||||
/// One or more timer expirations are pending.
|
||||
pub timer: bool,
|
||||
/// One or more cross-thread wake notifications are pending.
|
||||
pub wake: bool,
|
||||
}
|
||||
|
||||
pub struct Reactor {
|
||||
/// Low-level Linux runtime driver backed by `io_uring`.
|
||||
pub struct Driver {
|
||||
ring: IoUring,
|
||||
notifier: Arc<NotifierInner>,
|
||||
next_token: Cell<u64>,
|
||||
@@ -77,11 +85,16 @@ pub struct Reactor {
|
||||
completions: RefCell<BTreeMap<u64, CompletionHandler>>,
|
||||
}
|
||||
|
||||
pub fn create() -> io::Result<(Reactor, ThreadNotifier)> {
|
||||
create_reactor()
|
||||
/// Creates a new driver and its paired [`ThreadNotifier`].
|
||||
pub fn create() -> io::Result<(Driver, ThreadNotifier)> {
|
||||
create_driver()
|
||||
}
|
||||
|
||||
pub fn create_reactor() -> io::Result<(Reactor, ThreadNotifier)> {
|
||||
/// Creates a new driver and its paired [`ThreadNotifier`].
|
||||
///
|
||||
/// This is identical to [`create`] and exists as a more explicit name for callers that want to
|
||||
/// emphasize driver construction.
|
||||
pub fn create_driver() -> io::Result<(Driver, ThreadNotifier)> {
|
||||
let ring = IoUring::new(64)?;
|
||||
let notifier = Arc::new(NotifierInner {
|
||||
ring_fd: ring.ring_fd(),
|
||||
@@ -89,7 +102,7 @@ pub fn create_reactor() -> io::Result<(Reactor, ThreadNotifier)> {
|
||||
});
|
||||
|
||||
Ok((
|
||||
Reactor {
|
||||
Driver {
|
||||
ring,
|
||||
notifier: Arc::clone(¬ifier),
|
||||
next_token: Cell::new(1),
|
||||
@@ -102,7 +115,7 @@ pub fn create_reactor() -> io::Result<(Reactor, ThreadNotifier)> {
|
||||
))
|
||||
}
|
||||
|
||||
impl Reactor {
|
||||
impl Driver {
|
||||
pub(crate) fn bind_current_thread(&self) {
|
||||
self.ring.bind_current_thread();
|
||||
}
|
||||
@@ -111,6 +124,7 @@ impl Reactor {
|
||||
self.ring.unbind_current_thread();
|
||||
}
|
||||
|
||||
/// Polls the driver without blocking.
|
||||
pub fn poll(&self) -> io::Result<Option<ReadyEvents>> {
|
||||
let mut ready = ReadyEvents::default();
|
||||
let saw_any = self
|
||||
@@ -119,10 +133,14 @@ impl Reactor {
|
||||
if saw_any { Ok(Some(ready)) } else { Ok(None) }
|
||||
}
|
||||
|
||||
/// Blocks until at least one completion is available.
|
||||
pub fn wait(&self) -> io::Result<()> {
|
||||
self.ring.wait_for_cqe()
|
||||
}
|
||||
|
||||
/// Updates the currently armed timer deadline.
|
||||
///
|
||||
/// Passing `None` removes any active timer.
|
||||
pub fn rearm_timer(&self, deadline: Option<Duration>) -> io::Result<()> {
|
||||
match (self.active_timer_token.get(), deadline) {
|
||||
(Some(active), Some(deadline)) => {
|
||||
@@ -171,6 +189,7 @@ impl Reactor {
|
||||
})
|
||||
}
|
||||
|
||||
/// Drains the accumulated wake notification count.
|
||||
pub fn drain_wake(&self) -> io::Result<u64> {
|
||||
let wakes = self.pending_wakes.replace(0);
|
||||
if wakes == 0 {
|
||||
@@ -183,6 +202,7 @@ impl Reactor {
|
||||
}
|
||||
}
|
||||
|
||||
/// Drains the accumulated timer-expiration count.
|
||||
pub fn drain_timer(&self) -> io::Result<u64> {
|
||||
let timers = self.pending_timers.replace(0);
|
||||
if timers == 0 {
|
||||
@@ -234,12 +254,13 @@ impl Reactor {
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Reactor {
|
||||
impl Drop for Driver {
|
||||
fn drop(&mut self) {
|
||||
self.notifier.closed.store(true, Ordering::Release);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the current monotonic time used by the runtime timer system.
|
||||
pub fn monotonic_now() -> io::Result<Duration> {
|
||||
let mut now = std::mem::MaybeUninit::<libc::timespec>::uninit();
|
||||
let result = unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, now.as_mut_ptr()) };
|
||||
@@ -268,16 +289,16 @@ fn decode_token_kind(token: u64) -> Option<CompletionKind> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{create_reactor, monotonic_now};
|
||||
use super::{create_driver, monotonic_now};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
#[test]
|
||||
fn notifier_wakes_target_ring() {
|
||||
let (sender, _) = create_reactor().expect("sender reactor should initialize");
|
||||
let (sender, _) = create_driver().expect("sender driver should initialize");
|
||||
sender.bind_current_thread();
|
||||
|
||||
let (target, notifier) = create_reactor().expect("target reactor should initialize");
|
||||
let (target, notifier) = create_driver().expect("target driver should initialize");
|
||||
notifier.notify().expect("notify should succeed");
|
||||
|
||||
let ready = loop {
|
||||
@@ -295,7 +316,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn notifier_wakes_target_ring_from_plain_thread() {
|
||||
let (target, notifier) = create_reactor().expect("target reactor should initialize");
|
||||
let (target, notifier) = create_driver().expect("target driver should initialize");
|
||||
|
||||
thread::spawn(move || {
|
||||
notifier.notify().expect("notify should succeed");
|
||||
@@ -317,14 +338,14 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn timeout_reports_deadlines() {
|
||||
let (reactor, _notifier) = create_reactor().expect("reactor should initialize");
|
||||
let (driver, _notifier) = create_driver().expect("driver should initialize");
|
||||
let deadline = monotonic_now().expect("clock should work") + Duration::from_millis(20);
|
||||
reactor
|
||||
driver
|
||||
.rearm_timer(Some(deadline))
|
||||
.expect("timer should arm");
|
||||
|
||||
let ready = loop {
|
||||
if let Some(ready) = reactor.poll().expect("poll should succeed") {
|
||||
if let Some(ready) = driver.poll().expect("poll should succeed") {
|
||||
break ready;
|
||||
}
|
||||
thread::sleep(Duration::from_millis(5));
|
||||
@@ -332,9 +353,6 @@ mod tests {
|
||||
|
||||
assert!(ready.timer);
|
||||
assert!(!ready.wake);
|
||||
assert_eq!(
|
||||
reactor.drain_timer().expect("timer drain should succeed"),
|
||||
1
|
||||
);
|
||||
assert_eq!(driver.drain_timer().expect("timer drain should succeed"), 1);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
pub mod driver;
|
||||
pub mod mesh_alloc;
|
||||
pub mod reactor;
|
||||
pub mod runtime;
|
||||
pub(crate) mod uring;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//! Public runtime loop and worker-thread primitives.
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::{BTreeMap, VecDeque};
|
||||
use std::future::Future;
|
||||
@@ -9,7 +11,7 @@ use std::sync::{Arc, Mutex, MutexGuard};
|
||||
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
|
||||
use std::time::Duration;
|
||||
|
||||
use super::reactor::{Reactor, ThreadNotifier, create as create_reactor, monotonic_now};
|
||||
use super::driver::{Driver, ThreadNotifier, create_driver, monotonic_now};
|
||||
|
||||
type LocalTask = Box<dyn FnOnce() + 'static>;
|
||||
type SendTask = Box<dyn FnOnce() + Send + 'static>;
|
||||
@@ -19,16 +21,19 @@ type LocalBoxFuture = Pin<Box<dyn Future<Output = ()> + 'static>>;
|
||||
static mut CURRENT_THREAD: *mut ThreadState = ptr::null_mut();
|
||||
|
||||
#[derive(Clone)]
|
||||
/// Handle for queueing work onto a specific runtime thread.
|
||||
pub struct ThreadHandle {
|
||||
shared: Arc<ThreadShared>,
|
||||
}
|
||||
|
||||
/// Handle for a worker runtime thread spawned with [`spawn_worker`].
|
||||
pub struct WorkerHandle {
|
||||
thread: ThreadHandle,
|
||||
completion: Arc<WorkerCompletion>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
/// Handle returned by [`set_timeout`].
|
||||
pub struct TimeoutHandle {
|
||||
id: usize,
|
||||
owner: *const ThreadState,
|
||||
@@ -36,20 +41,37 @@ pub struct TimeoutHandle {
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
/// Handle returned by [`set_interval`].
|
||||
pub struct IntervalHandle {
|
||||
id: usize,
|
||||
owner: *const ThreadState,
|
||||
_local: Rc<()>,
|
||||
}
|
||||
|
||||
/// Handle returned by [`queue_future`].
|
||||
///
|
||||
/// Awaiting a join handle yields the output of the queued future.
|
||||
pub struct JoinHandle<T> {
|
||||
state: Rc<JoinState<T>>,
|
||||
}
|
||||
|
||||
/// Future returned by [`yield_now`].
|
||||
///
|
||||
/// Awaiting this future will immediately yield control back to the runtime scheduler, allowing other queued microtasks
|
||||
/// to run before the current task continues executing. Note that continuation of futures runs as a microtask, so this
|
||||
/// can only yield to other microtasks and not to macrotasks (driver events such as file or network I/O, timers, or
|
||||
/// channel messages).
|
||||
pub struct YieldNow {
|
||||
yielded: bool,
|
||||
}
|
||||
|
||||
/// Returns a handle for the current runtime thread.
|
||||
///
|
||||
/// If the current thread has not yet entered the runtime, the runtime state is initialized lazily.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the runtime cannot initialize its driver for the current thread.
|
||||
pub fn current_thread_handle() -> ThreadHandle {
|
||||
current_thread().handle()
|
||||
}
|
||||
@@ -58,10 +80,17 @@ pub(crate) fn try_current_thread_handle() -> Option<ThreadHandle> {
|
||||
unsafe { (!CURRENT_THREAD.is_null()).then(|| (*CURRENT_THREAD).handle()) }
|
||||
}
|
||||
|
||||
pub(crate) fn with_current_reactor<T>(f: impl FnOnce(&Reactor) -> T) -> T {
|
||||
f(¤t_thread().reactor)
|
||||
pub(crate) fn with_current_driver<T>(f: impl FnOnce(&Driver) -> T) -> T {
|
||||
f(¤t_thread().driver)
|
||||
}
|
||||
|
||||
/// Queues a macrotask on the current runtime thread.
|
||||
///
|
||||
/// The task runs after all currently-queued macrotasks, and after all microtasks.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the runtime cannot initialize its state for the current thread.
|
||||
pub fn queue_task<F>(task: F)
|
||||
where
|
||||
F: FnOnce() + 'static,
|
||||
@@ -69,6 +98,14 @@ where
|
||||
push_local_macrotask(Box::new(task));
|
||||
}
|
||||
|
||||
/// Queues a microtask on the current runtime thread.
|
||||
///
|
||||
/// Microtasks run before the next macrotask turn, mirroring JavaScript-style event loop
|
||||
/// semantics.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the runtime cannot initialize its state for the current thread.
|
||||
pub fn queue_microtask<F>(task: F)
|
||||
where
|
||||
F: FnOnce() + 'static,
|
||||
@@ -79,6 +116,11 @@ where
|
||||
.push_back(Box::new(task));
|
||||
}
|
||||
|
||||
/// Schedules a one-shot timer on the current runtime thread.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the runtime cannot initialize its state for the current thread.
|
||||
pub fn set_timeout<F>(delay: Duration, callback: F) -> TimeoutHandle
|
||||
where
|
||||
F: FnOnce() + 'static,
|
||||
@@ -98,10 +140,22 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Cancels a timeout previously created by [`set_timeout`].
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if called from a different runtime thread than the one that created `handle`.
|
||||
pub fn clear_timeout(handle: &TimeoutHandle) {
|
||||
clear_timer(handle.owner, handle.id);
|
||||
}
|
||||
|
||||
/// Schedules a repeating timer on the current runtime thread.
|
||||
///
|
||||
/// The callback is invoked once per interval until the handle is cleared.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the runtime cannot initialize its state for the current thread.
|
||||
pub fn set_interval<F>(delay: Duration, callback: F) -> IntervalHandle
|
||||
where
|
||||
F: FnMut() + 'static,
|
||||
@@ -126,10 +180,33 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Cancels an interval previously created by [`set_interval`].
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if called from a different runtime thread than the one that created `handle`.
|
||||
pub fn clear_interval(handle: &IntervalHandle) {
|
||||
clear_timer(handle.owner, handle.id);
|
||||
}
|
||||
|
||||
/// Queues a future on the current runtime thread.
|
||||
///
|
||||
/// The future is scheduled immediately and can be awaited through the returned [`JoinHandle`].
|
||||
///
|
||||
/// The future will be driven to completion regardless or whether the join handle is polled or dropped, so this function
|
||||
/// can be used as a convenient way to spawn detached async tasks on the current thread.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # let _ = || {
|
||||
/// let handle = ruin_runtime::queue_future(async { 42usize });
|
||||
/// # };
|
||||
/// ```
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the runtime cannot initialize its state for the current thread.
|
||||
pub fn queue_future<F>(future: F) -> JoinHandle<F::Output>
|
||||
where
|
||||
F: Future + 'static,
|
||||
@@ -150,13 +227,21 @@ where
|
||||
JoinHandle { state }
|
||||
}
|
||||
|
||||
/// Spawns a worker runtime thread.
|
||||
///
|
||||
/// `initial_task` is queued onto the worker as its first macrotask. `on_exit` runs on the parent
|
||||
/// runtime thread after the worker shuts down.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the worker thread or its driver cannot be created.
|
||||
pub fn spawn_worker<Init, Exit>(initial_task: Init, on_exit: Exit) -> WorkerHandle
|
||||
where
|
||||
Init: FnOnce() + Send + 'static,
|
||||
Exit: FnOnce() + 'static,
|
||||
{
|
||||
let parent = current_thread();
|
||||
let (reactor, notifier) = create_reactor().expect("worker reactor should initialize");
|
||||
let (driver, notifier) = create_driver().expect("worker driver should initialize");
|
||||
let shared = Arc::new(ThreadShared::new(notifier));
|
||||
let handle = ThreadHandle {
|
||||
shared: Arc::clone(&shared),
|
||||
@@ -175,7 +260,7 @@ where
|
||||
std::thread::Builder::new()
|
||||
.name("ruin-runtime-worker".into())
|
||||
.spawn(move || {
|
||||
install_thread(shared, reactor, Some(worker_completion));
|
||||
install_thread(shared, driver, Some(worker_completion));
|
||||
queue_task(initial_task);
|
||||
run();
|
||||
})
|
||||
@@ -187,6 +272,14 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs the current runtime thread until no work, timers, child workers, or async operations
|
||||
/// remain.
|
||||
///
|
||||
/// This is the main event loop entry point used by the proc-macro entry attributes.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if runtime initialization fails or if the underlying driver returns an unexpected error.
|
||||
pub fn run() {
|
||||
let _ = current_thread();
|
||||
|
||||
@@ -223,7 +316,7 @@ pub fn run() {
|
||||
|
||||
if has_pending_timers() || state.has_live_children() || state.has_live_async_operations() {
|
||||
state.shared.closing.store(false, Ordering::Release);
|
||||
state.reactor.wait().expect("reactor wait should succeed");
|
||||
state.driver.wait().expect("driver wait should succeed");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -240,16 +333,20 @@ pub fn run() {
|
||||
}
|
||||
|
||||
fn drain_all() {
|
||||
drain_reactor_events();
|
||||
drain_driver_events();
|
||||
drain_remote_tasks();
|
||||
drain_completed_workers();
|
||||
}
|
||||
|
||||
/// Returns a future that yields back to the runtime scheduler once.
|
||||
pub fn yield_now() -> YieldNow {
|
||||
YieldNow { yielded: false }
|
||||
}
|
||||
|
||||
impl ThreadHandle {
|
||||
/// Queues a macrotask onto this runtime thread.
|
||||
///
|
||||
/// Returns `false` if the target thread is already closed.
|
||||
pub fn queue_task<F>(&self, task: F) -> bool
|
||||
where
|
||||
F: FnOnce() + Send + 'static,
|
||||
@@ -257,6 +354,9 @@ impl ThreadHandle {
|
||||
self.shared.enqueue_macro(Box::new(task))
|
||||
}
|
||||
|
||||
/// Queues a microtask onto this runtime thread.
|
||||
///
|
||||
/// Returns `false` if the target thread is already closed.
|
||||
pub fn queue_microtask<F>(&self, task: F) -> bool
|
||||
where
|
||||
F: FnOnce() + Send + 'static,
|
||||
@@ -264,6 +364,7 @@ impl ThreadHandle {
|
||||
self.shared.enqueue_micro(Box::new(task))
|
||||
}
|
||||
|
||||
/// Returns `true` if the target runtime thread has shut down.
|
||||
pub fn is_closed(&self) -> bool {
|
||||
self.shared.closed.load(Ordering::Acquire)
|
||||
}
|
||||
@@ -282,6 +383,9 @@ impl ThreadHandle {
|
||||
}
|
||||
|
||||
impl WorkerHandle {
|
||||
/// Queues a macrotask onto the worker thread.
|
||||
///
|
||||
/// Returns `false` if the worker has already shut down.
|
||||
pub fn queue_task<F>(&self, task: F) -> bool
|
||||
where
|
||||
F: FnOnce() + Send + 'static,
|
||||
@@ -289,6 +393,9 @@ impl WorkerHandle {
|
||||
self.thread.queue_task(task)
|
||||
}
|
||||
|
||||
/// Queues a microtask onto the worker thread.
|
||||
///
|
||||
/// Returns `false` if the worker has already shut down.
|
||||
pub fn queue_microtask<F>(&self, task: F) -> bool
|
||||
where
|
||||
F: FnOnce() + Send + 'static,
|
||||
@@ -296,10 +403,12 @@ impl WorkerHandle {
|
||||
self.thread.queue_microtask(task)
|
||||
}
|
||||
|
||||
/// Returns `true` once the worker thread has fully exited.
|
||||
pub fn is_finished(&self) -> bool {
|
||||
self.completion.finished.load(Ordering::Acquire)
|
||||
}
|
||||
|
||||
/// Returns a generic [`ThreadHandle`] for the worker thread.
|
||||
pub fn thread(&self) -> ThreadHandle {
|
||||
self.thread.clone()
|
||||
}
|
||||
@@ -328,7 +437,7 @@ impl Future for YieldNow {
|
||||
}
|
||||
|
||||
struct ThreadState {
|
||||
reactor: Reactor,
|
||||
driver: Driver,
|
||||
shared: Arc<ThreadShared>,
|
||||
worker_completion: Option<Arc<WorkerCompletion>>,
|
||||
local_microtasks: RefCell<VecDeque<LocalTask>>,
|
||||
@@ -341,11 +450,11 @@ struct ThreadState {
|
||||
impl ThreadState {
|
||||
fn new(
|
||||
shared: Arc<ThreadShared>,
|
||||
reactor: Reactor,
|
||||
driver: Driver,
|
||||
worker_completion: Option<Arc<WorkerCompletion>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
reactor,
|
||||
driver,
|
||||
shared,
|
||||
worker_completion,
|
||||
local_microtasks: RefCell::new(VecDeque::new()),
|
||||
@@ -695,11 +804,11 @@ unsafe fn future_task_drop(data: *const ()) {
|
||||
fn current_thread() -> &'static ThreadState {
|
||||
unsafe {
|
||||
if CURRENT_THREAD.is_null() {
|
||||
let (reactor, notifier) = create_reactor().expect("runtime reactor should initialize");
|
||||
let (driver, notifier) = create_driver().expect("runtime driver should initialize");
|
||||
let shared = Arc::new(ThreadShared::new(notifier));
|
||||
let state = Box::new(ThreadState::new(shared, reactor, None));
|
||||
let state = Box::new(ThreadState::new(shared, driver, None));
|
||||
let state = Box::into_raw(state);
|
||||
(*state).reactor.bind_current_thread();
|
||||
(*state).driver.bind_current_thread();
|
||||
CURRENT_THREAD = state;
|
||||
}
|
||||
|
||||
@@ -713,14 +822,14 @@ fn current_thread_ptr() -> *const ThreadState {
|
||||
|
||||
fn install_thread(
|
||||
shared: Arc<ThreadShared>,
|
||||
reactor: Reactor,
|
||||
driver: Driver,
|
||||
worker_completion: Option<Arc<WorkerCompletion>>,
|
||||
) {
|
||||
unsafe {
|
||||
debug_assert!(CURRENT_THREAD.is_null(), "thread runtime already installed");
|
||||
let state = Box::new(ThreadState::new(shared, reactor, worker_completion));
|
||||
let state = Box::new(ThreadState::new(shared, driver, worker_completion));
|
||||
let state = Box::into_raw(state);
|
||||
(*state).reactor.bind_current_thread();
|
||||
(*state).driver.bind_current_thread();
|
||||
CURRENT_THREAD = state;
|
||||
}
|
||||
}
|
||||
@@ -731,18 +840,18 @@ fn teardown_thread() {
|
||||
CURRENT_THREAD = ptr::null_mut();
|
||||
|
||||
if !state.is_null() {
|
||||
(*state).reactor.unbind_current_thread();
|
||||
(*state).driver.unbind_current_thread();
|
||||
drop(Box::from_raw(state));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn drain_reactor_events() {
|
||||
fn drain_driver_events() {
|
||||
loop {
|
||||
let ready = current_thread()
|
||||
.reactor
|
||||
.driver
|
||||
.poll()
|
||||
.expect("reactor poll should succeed");
|
||||
.expect("driver poll should succeed");
|
||||
|
||||
let Some(ready) = ready else {
|
||||
break;
|
||||
@@ -751,13 +860,13 @@ fn drain_reactor_events() {
|
||||
let state = current_thread();
|
||||
if ready.wake {
|
||||
let _ = state
|
||||
.reactor
|
||||
.driver
|
||||
.drain_wake()
|
||||
.expect("wake drain should succeed");
|
||||
}
|
||||
if ready.timer {
|
||||
let _ = state
|
||||
.reactor
|
||||
.driver
|
||||
.drain_timer()
|
||||
.expect("timer drain should succeed");
|
||||
dispatch_expired_timers();
|
||||
@@ -906,9 +1015,9 @@ fn dispatch_expired_timers() {
|
||||
fn rearm_thread_timer() {
|
||||
let deadline = current_thread().timers.borrow().peek_deadline();
|
||||
current_thread()
|
||||
.reactor
|
||||
.driver
|
||||
.rearm_timer(deadline)
|
||||
.expect("timerfd rearm should succeed");
|
||||
.expect("driver timer rearm should succeed");
|
||||
}
|
||||
|
||||
fn deadline_from_now(delay: Duration) -> Duration {
|
||||
|
||||
Reference in New Issue
Block a user