Functional parity with linux

This commit is contained in:
Will Temple
2026-05-15 13:31:59 -07:00
parent 861bf63621
commit 67400f1499
17 changed files with 2221 additions and 458 deletions

View File

@@ -77,7 +77,7 @@ pub use platform::current::driver::{
pub use platform::current::runtime::{
IntervalHandle, JoinHandle, ThreadHandle, TimeoutHandle, WorkerHandle, clear_interval,
clear_timeout, current_thread_handle, queue_future, queue_microtask, queue_task, run,
set_interval, set_timeout, spawn_worker, yield_now,
run_ready_tasks, run_until_stalled, set_interval, set_timeout, spawn_worker, yield_now,
};
/// Public mesh-allocator surface re-exported from the Linux x86_64 backend.
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]

View File

@@ -478,6 +478,99 @@ pub fn run() {
}
}
/// Drains ready work on the current runtime thread without blocking for future work.
///
/// Unlike [`run`], this returns as soon as there are no immediately runnable
/// microtasks or macrotasks left. It is intended for host integrations that
/// need to re-enter the scheduler while an outer platform loop remains active.
pub fn run_until_stalled() {
let _ = current_thread();
loop {
drain_all();
let mut microtasks_run: u64 = 0;
while let Some(task) = pop_microtask() {
task();
microtasks_run += 1;
drain_all();
}
if microtasks_run >= MICROTASK_STARVATION_THRESHOLD {
tracing::warn!(
target: trace_targets::SCHEDULER,
event = "microtask_starvation",
count = microtasks_run,
"microtask queue ran {microtasks_run} tasks in a single turn; macrotask handlers may be starved",
);
}
if let Some(task) = pop_macrotask() {
task();
continue;
}
drain_all();
if has_ready_work() {
continue;
}
current_thread()
.shared
.closing
.store(false, Ordering::Release);
return;
}
}
/// Drains already-queued work on the current runtime thread without polling the
/// driver for timers or I/O readiness.
///
/// This is intended for host integrations that need to flush application work
/// from inside a host callback without re-entering timer callbacks.
pub fn run_ready_tasks() {
let _ = current_thread();
loop {
drain_remote_tasks();
drain_completed_workers();
let mut microtasks_run: u64 = 0;
while let Some(task) = pop_microtask() {
task();
microtasks_run += 1;
drain_remote_tasks();
drain_completed_workers();
}
if microtasks_run >= MICROTASK_STARVATION_THRESHOLD {
tracing::warn!(
target: trace_targets::SCHEDULER,
event = "microtask_starvation",
count = microtasks_run,
"microtask queue ran {microtasks_run} tasks in a single turn; macrotask handlers may be starved",
);
}
if let Some(task) = pop_macrotask() {
task();
continue;
}
drain_remote_tasks();
drain_completed_workers();
if has_ready_work() {
continue;
}
current_thread()
.shared
.closing
.store(false, Ordering::Release);
return;
}
}
fn drain_all() {
drain_driver_events();
drain_remote_tasks();

View File

@@ -480,6 +480,99 @@ pub fn run() {
}
}
/// Drains ready work on the current runtime thread without blocking for future work.
///
/// Unlike [`run`], this returns as soon as there are no immediately runnable
/// microtasks or macrotasks left. It is intended for host integrations that
/// need to re-enter the scheduler while an outer platform loop remains active.
pub fn run_until_stalled() {
let _ = current_thread();
loop {
drain_all();
let mut microtasks_run: u64 = 0;
while let Some(task) = pop_microtask() {
task();
microtasks_run += 1;
drain_all();
}
if microtasks_run >= MICROTASK_STARVATION_THRESHOLD {
tracing::warn!(
target: trace_targets::SCHEDULER,
event = "microtask_starvation",
count = microtasks_run,
"microtask queue ran {microtasks_run} tasks in a single turn; macrotask handlers may be starved",
);
}
if let Some(task) = pop_macrotask() {
task();
continue;
}
drain_all();
if has_ready_work() {
continue;
}
current_thread()
.shared
.closing
.store(false, Ordering::Release);
return;
}
}
/// Drains already-queued work on the current runtime thread without polling the
/// driver for timers or I/O readiness.
///
/// This is intended for host integrations that need to flush application work
/// from inside a host callback without re-entering timer callbacks.
pub fn run_ready_tasks() {
let _ = current_thread();
loop {
drain_remote_tasks();
drain_completed_workers();
let mut microtasks_run: u64 = 0;
while let Some(task) = pop_microtask() {
task();
microtasks_run += 1;
drain_remote_tasks();
drain_completed_workers();
}
if microtasks_run >= MICROTASK_STARVATION_THRESHOLD {
tracing::warn!(
target: trace_targets::SCHEDULER,
event = "microtask_starvation",
count = microtasks_run,
"microtask queue ran {microtasks_run} tasks in a single turn; macrotask handlers may be starved",
);
}
if let Some(task) = pop_macrotask() {
task();
continue;
}
drain_remote_tasks();
drain_completed_workers();
if has_ready_work() {
continue;
}
current_thread()
.shared
.closing
.store(false, Ordering::Release);
return;
}
}
fn drain_all() {
drain_driver_events();
drain_remote_tasks();