Merge origin/main into macos

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Will Temple
2026-05-16 16:38:10 -04:00
66 changed files with 9558 additions and 2326 deletions

View File

@@ -1,4 +1,6 @@
//! Public runtime driver primitives.
//! RUIN Runtime Driver for Linux x86_64.
//!
//!
use std::cell::Cell;
use std::cell::RefCell;
@@ -88,12 +90,21 @@ pub struct ReadyEvents {
/// Low-level Linux runtime driver backed by `io_uring`.
pub struct Driver {
/// The `io_uring` instance driving this runtime thread.
ring: IoUring,
/// Shared notifier that other threads can use to wake this runtime thread.
notifier: Arc<NotifierInner>,
/// Next sequence number for generated completion tokens.
next_token: Cell<u64>,
/// The token of the currently active timer, if any timer is armed.
active_timer_token: Cell<Option<u64>>,
/// Accumulated count of pending wake notifications that have not yet been triggered.
pending_wakes: Cell<u64>,
/// Accumulated count of pending timer expirations that have not yet been triggered.
pending_timers: Cell<u64>,
/// Map of active completion tokens to associated handlers. When a CQE is received with a token in this map, the
/// corresponding handler will be invoked with the CQE and removed from the map. This is the core mechanism by which
/// async operations are tracked and dispatched to their continuations.
completions: RefCell<HashMap<u64, CompletionHandler>>,
}

View File

@@ -50,6 +50,12 @@ pub struct TimeoutHandle {
_local: Rc<()>,
}
impl TimeoutHandle {
pub fn clear(&self) {
clear_timeout(self);
}
}
#[derive(Clone)]
/// Handle returned by [`set_interval`].
pub struct IntervalHandle {
@@ -58,6 +64,12 @@ pub struct IntervalHandle {
_local: Rc<()>,
}
impl IntervalHandle {
pub fn clear(&self) {
clear_interval(self);
}
}
/// Handle returned by [`queue_future`].
///
/// Awaiting a join handle yields the output of the queued future.
@@ -68,9 +80,10 @@ pub struct JoinHandle<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
/// to run before the current task continues executing. Note that continuations of futures run as microtasks, 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).
/// channel messages). To yield to macrotasks, you must allow the flow of execution to return to the runtime event loop
/// and flush the full microtask queue, for example by awaiting a timer.
pub struct YieldNow {
yielded: bool,
}
@@ -213,17 +226,19 @@ where
);
if delay.is_zero() {
unimplemented!("Zero-delay intervals are not yet implemented.")
// TODO: vibeshit got this completely wrong
// Zero-delay intervals never touch the timer heap or arm an io_uring
// timer (a past-deadline kernel timer would fire on every event loop
// iteration, spinning the runtime at 100 % CPU). Instead the callback
// is stored in `immediate_intervals` and self-schedules as a macrotask
// each turn, mirroring JS `setInterval(f, 0)` semantics.
let callback = Rc::new(RefCell::new(Box::new(callback) as Box<dyn FnMut()>));
current_thread()
.immediate_intervals
.borrow_mut()
.insert(id, Rc::clone(&callback));
schedule_immediate_interval(owner, id);
// let callback = Rc::new(RefCell::new(Box::new(callback) as Box<dyn FnMut()>));
// current_thread()
// .immediate_intervals
// .borrow_mut()
// .insert(id, Rc::clone(&callback));
// schedule_immediate_interval(owner, id);
} else {
let deadline = deadline_from_now(delay);
#[cfg(debug_assertions)]
@@ -660,6 +675,8 @@ impl Future for YieldNow {
}
}
type ImmediateIntervals = RefCell<HashMap<usize, Rc<RefCell<Box<dyn FnMut()>>>>>;
struct ThreadState {
driver: Driver,
shared: Arc<ThreadShared>,
@@ -669,7 +686,7 @@ struct ThreadState {
timers: RefCell<TimerHeap>,
/// Zero-delay intervals bypasses the timer heap entirely. Each entry
/// re-enqueues itself as a macrotask on every turn.
immediate_intervals: RefCell<HashMap<usize, IntervalCallback>>,
immediate_intervals: ImmediateIntervals,
next_timer_id: Cell<usize>,
children: RefCell<Vec<ChildWorker>>,
}
@@ -1251,31 +1268,32 @@ fn clear_timer(owner: *const ThreadState, id: usize) {
}
}
/// Enqueues one macrotask turn for a zero-delay interval.
///
/// The macrotask checks whether the interval is still live (not cleared), fires
/// the callback, and re-enqueues itself for the next turn.
fn schedule_immediate_interval(owner: *const ThreadState, id: usize) {
push_local_macrotask(Box::new(move || {
let callback = current_thread()
.immediate_intervals
.borrow()
.get(&id)
.map(Rc::clone);
let Some(callback) = callback else {
return; // interval was cleared before this turn ran
};
(callback.borrow_mut())();
// Re-enqueue for the next turn if still live.
if current_thread()
.immediate_intervals
.borrow()
.contains_key(&id)
{
schedule_immediate_interval(owner, id);
}
}));
}
// TODO: vibeshit got this completely wrong
// /// Enqueues one macrotask turn for a zero-delay interval.
// ///
// /// The macrotask checks whether the interval is still live (not cleared), fires
// /// the callback, and re-enqueues itself for the next turn.
// fn schedule_immediate_interval(owner: *const ThreadState, id: usize) {
// push_local_macrotask(Box::new(move || {
// let callback = current_thread()
// .immediate_intervals
// .borrow()
// .get(&id)
// .map(Rc::clone);
// let Some(callback) = callback else {
// return; // interval was cleared before this turn ran
// };
// (callback.borrow_mut())();
// // Re-enqueue for the next turn if still live.
// if current_thread()
// .immediate_intervals
// .borrow()
// .contains_key(&id)
// {
// schedule_immediate_interval(owner, id);
// }
// }));
// }
fn dispatch_expired_timers() {
let now = deadline_from_now(Duration::ZERO);

View File

@@ -58,6 +58,12 @@ pub struct IntervalHandle {
_local: Rc<()>,
}
impl IntervalHandle {
pub fn clear(&self) {
clear_interval(self);
}
}
/// Handle returned by [`queue_future`].
///
/// Awaiting a join handle yields the output of the queued future.