This commit is contained in:
Kenneth Allen 2026-09-25 15:24:17 +10:00
parent 5bb857dabd
commit 891788af2a
4 changed files with 409 additions and 58 deletions

351
Cargo.lock generated
View File

@ -2,46 +2,154 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "aho-corasick"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba"
dependencies = [
"memchr",
]
[[package]]
name = "anstream"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
[[package]]
name = "anstyle-parse"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
dependencies = [
"anstyle",
"once_cell_polyfill",
"windows-sys",
]
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06"
[[package]]
name = "bitvec"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddcec3d12c579d40898fe0a9a358a803c23e9c52ca3c425707f81c9436211837"
dependencies = [
"funty",
"radium",
"tap",
"wyz",
]
[[package]]
name = "cfg-if"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
[[package]]
name = "colorchoice"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
[[package]]
name = "curio"
version = "0.1.0"
dependencies = [
"bitvec",
"env_logger",
"io-uring",
"libc",
"log",
"send_wrapper",
"slab",
]
[[package]]
name = "funty"
name = "defmt"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1"
dependencies = [
"bitflags 1.3.2",
"defmt-macros",
]
[[package]]
name = "defmt-macros"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8"
dependencies = [
"defmt-parser",
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]]
name = "defmt-parser"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e"
dependencies = [
"thiserror",
]
[[package]]
name = "env_filter"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
checksum = "900d271a03799a1ee8d1ca9b19893b48ca674a9284fefcfb85f05e74ed314217"
dependencies = [
"log",
"regex",
]
[[package]]
name = "env_logger"
version = "0.11.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de671bd27a75a797dc9ae289ba1e77276e75e2026408aab65185384e2d5cd3f6"
dependencies = [
"anstream",
"anstyle",
"env_filter",
"jiff",
"log",
]
[[package]]
name = "io-uring"
@ -49,11 +157,54 @@ version = "0.7.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed3bd0ecfbb87805f538bb7b32e5239ca0763890c623e349860ecba69469f2bb"
dependencies = [
"bitflags",
"bitflags 2.13.2",
"cfg-if",
"libc",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
[[package]]
name = "jiff"
version = "0.2.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1baf72f08796de0260609515130699b890ac25f30e610ad894bc5856cafdb"
dependencies = [
"defmt",
"jiff-core",
"jiff-static",
"log",
"portable-atomic",
"portable-atomic-util",
"serde_core",
]
[[package]]
name = "jiff-core"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e52fe76043ccecc9005d2305ebaadf7d7fc0cc89ca6baa10a94d6bc68c7128c"
dependencies = [
"defmt",
"log",
]
[[package]]
name = "jiff-static"
version = "0.2.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "378268a1116ad67ae6228701118ac9f491d78fda38a40a1f1a9e1348de6f7212"
dependencies = [
"jiff-core",
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]]
name = "libc"
version = "0.2.189"
@ -61,10 +212,84 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
[[package]]
name = "radium"
version = "0.7.0"
name = "log"
version = "0.4.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
[[package]]
name = "memchr"
version = "2.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
[[package]]
name = "once_cell_polyfill"
version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]]
name = "portable-atomic"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
[[package]]
name = "portable-atomic-util"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10ab3eb7f3becc3a1cbc4f2c6f20267996cfc1a6467a873763411b136a122715"
dependencies = [
"portable-atomic",
]
[[package]]
name = "proc-macro2"
version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
[[package]]
name = "send_wrapper"
@ -72,6 +297,26 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
[[package]]
name = "serde_core"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
dependencies = [
"proc-macro2",
"quote",
"syn 3.0.6",
]
[[package]]
name = "slab"
version = "0.4.12"
@ -79,16 +324,70 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
[[package]]
name = "tap"
version = "1.0.1"
name = "syn"
version = "2.0.119"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "wyz"
version = "0.5.1"
name = "syn"
version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee"
dependencies = [
"tap",
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "2.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "2.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524"
dependencies = [
"proc-macro2",
"quote",
"syn 3.0.6",
]
[[package]]
name = "unicode-ident"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link",
]

View File

@ -4,8 +4,9 @@ version = "0.1.0"
edition = "2024"
[dependencies]
bitvec = "1.1.1"
env_logger = "0.11.11"
io-uring = "0.7.15"
libc = "0.2.189"
log = "0.4.34"
send_wrapper = "0.6.0"
slab = "0.4.12"

View File

@ -1,13 +1,16 @@
#![feature(local_waker)]
#![feature(waker_fn)]
#![feature(context_ext)]
use std::{
cell::RefCell, io::ErrorKind, pin::{Pin, pin}, rc::{Rc, Weak}, task::{Context, ContextBuilder, Poll, Waker, local_waker_fn, waker_fn}, time::Instant,
cell::RefCell, pin::Pin, rc::{Rc, Weak}, task::{ContextBuilder, Poll, local_waker_fn, waker_fn}, thread::sleep, time::Instant,
};
use io_uring::{IoUring, types::{SubmitArgs, Timespec}};
use libc::ETIME;
use io_uring::{
IoUring,
types::{SubmitArgs, Timespec},
};
use libc::{ETIME};
use log::trace;
use send_wrapper::SendWrapper;
use slab::Slab;
@ -29,7 +32,6 @@ pub struct RuntimeInner {
pub struct Runtime(Rc<RefCell<RuntimeInner>>);
struct RuntimeWeak(Weak<RefCell<RuntimeInner>>);
thread_local! {
static RT: RefCell<Option<Runtime>> = RefCell::new(None);
}
@ -64,7 +66,10 @@ impl Runtime {
pub fn spawn(&self, fut: Pin<Box<dyn Future<Output = ()>>>) {
let mut inner = self.0.borrow_mut();
let task_id = inner.tasks.insert(Task { fut: Some(fut), ready: true });
let task_id = inner.tasks.insert(Task {
fut: Some(fut),
ready: true,
});
inner.runqueue.push(task_id);
}
@ -74,26 +79,42 @@ impl Runtime {
pub fn run(&mut self) {
RT.set(Some(Runtime(Rc::clone(&self.0))));
while !self.0.borrow().tasks.is_empty() {
let mut lock = self.0.borrow_mut();
while !lock.tasks.is_empty() {
// Run until no ready tasks, no timers, no future CQEs
trace!("Polling tasks");
loop {
let task_id = {
let mut lock = self.0.borrow_mut();
let Some(task_id) = lock.runqueue.pop() else {
break;
};
trace!("Polling task {}", task_id);
lock.tasks[task_id].ready = false;
task_id
};
let waker = {
let inner = SendWrapper::new(self.downgrade());
waker_fn(move || {
if let Some(inner) = inner.0.upgrade() {
trace!("Waking {}", task_id);
let mut lock = inner.borrow_mut();
let ready = &mut lock.tasks[task_id].ready;
if !*ready {
trace!("Enqueueing {}", task_id);
*ready = true;
lock.runqueue.push(task_id);
}
}
})
};
let local_waker = {
let inner = SendWrapper::new(self.downgrade());
local_waker_fn(move || {
if let Some(inner) = inner.0.upgrade() {
trace!("Local waking {}", task_id);
let mut lock = inner.borrow_mut();
let ready = &mut lock.tasks[task_id].ready;
if !*ready {
trace!("Local enqueueing {}", task_id);
*ready = true;
lock.runqueue.push(task_id);
}
@ -101,46 +122,64 @@ impl Runtime {
})
};
let mut cx = ContextBuilder::from_waker(&waker)
.local_waker(&local_waker)
.build();
let mut task = self.0.borrow_mut().tasks[task_id].fut.take().unwrap();
match task.as_mut().poll(&mut cx) {
let mut task = lock.tasks[task_id].fut.take().unwrap();
drop(lock);
let outcome = task.as_mut().poll(&mut cx);
lock = self.0.borrow_mut();
match outcome {
Poll::Ready(()) => {
self.0.borrow_mut().tasks.remove(task_id);
lock.tasks.remove(task_id);
}
Poll::Pending => {
self.0.borrow_mut().tasks[task_id].fut = Some(task);
lock.tasks[task_id].fut = Some(task);
}
}
}
let now = Instant::now();
trace!("Polling timers");
let wait = loop {
let mut lock = self.0.borrow_mut();
match lock.timer.poll(now) {
timer::Status::Empty => break None,
timer::Status::Pending(deadline) => break Some(Timespec::from(deadline - now)),
timer::Status::Empty => {
trace!("No timers expired");
break None;
}
timer::Status::Pending(deadline) => {
trace!("Next timer expiring in {:?}", deadline - now);
break Some(Timespec::from(deadline - now));
}
timer::Status::Expired(waker) => {
trace!("Timer expired, waking");
drop(lock);
waker.wake();
lock = self.0.borrow_mut();
}
}
};
let mut args = SubmitArgs::new();
if let Some(wait) = &wait {
args = args.timespec(&wait);
trace!("Entering ring");
let want = match &wait {
Some(wait) => {
args = args.timespec(wait);
1
}
match self.0.borrow_mut().ring.submitter().submit_with_args(1, &args) {
None => 0,
};
match lock.ring.submitter().submit_with_args(want, &args) {
Ok(n) => {
debug_assert_eq!(n, 0);
}
Err(err) if err.raw_os_error() == Some(ETIME) => {},
Err(err) if err.raw_os_error() == Some(ETIME) && wait.is_some() => {}
e => {
e.expect("failed to enter ring");
},
}
}
}
trace!("Exiting");
}
}
#[cfg(test)]
@ -153,6 +192,7 @@ use super::*;
#[test]
fn it_works() {
env_logger::init();
let mut runtime = Runtime::new();
runtime.spawn(Box::pin(async {
println!("1");

View File

@ -1,4 +1,13 @@
use std::{borrow::BorrowMut as _, cell::RefCell, cmp::Reverse, collections::BinaryHeap, pin::Pin, rc::{Rc, Weak}, task::{Context, LocalWaker, Poll, Waker}, time::{Duration, Instant}};
use std::{
borrow::BorrowMut as _,
cell::RefCell,
cmp::Reverse,
collections::BinaryHeap,
pin::Pin,
rc::{Rc, Weak},
task::{Context, LocalWaker, Poll},
time::{Duration, Instant},
};
use slab::Slab;
@ -95,7 +104,9 @@ impl Drop for Timer {
pub fn delay_until(deadline: Instant) -> Timer {
Timer {
slot: RT.with_borrow(|rt| {
let rt = rt.as_ref().expect("called from outside curio runtime thread");
let rt = rt
.as_ref()
.expect("called from outside curio runtime thread");
let mut lock = rt.0.as_ref().borrow_mut();
lock.timer.insert(deadline)
}),