Wouldn’t it be cool if we could just use standard OS threads, blocking APIs, avoid new shinies like io_uring, but still get to cancel any work reliably?
Wish more was said about this: why would that be cool? I get that having robust cancellation in standard threads is cool, but why do we want to avoid io_uring?
Programming asynchronous code is hard. Execution is split up, you have extra state machine to handle, extra resources to manage that need to survive across async boundaries. And by asynchronous, I mean either callbacks or manually checked completions from some event system. Modern languages hide that under async/await, which is much better from DX perspective, but still leads to split in the ecosystem, and it's hard to optimize across async boundaries.
This is an example why Go is such a successful language, in my view. It hides the async complexity and allows you to pretend you have a simple continuous thread of execution. It's just cheaper than system threads. Imagine if operating system threads and the blocking syscalls were this efficient.
I've spent the last year building a similar runtime for Zig. Purely because I want my applications to forget they are using things like io_uring in the background.
io_uring has been one of the greatest sources of exploits for the Linux kernel in years. io_uring has resulted in so many practical privilege escalation attacks that many containers completely block it, and companies like Google keep it entirely disabled. RHEL also ships a kernel without it by default.
Comments
Oh man this finishes too early, I would want to read more!
Agreed.
There's this line:
Wish more was said about this: why would that be cool? I get that having robust cancellation in standard threads is cool, but why do we want to avoid io_uring?
Programming asynchronous code is hard. Execution is split up, you have extra state machine to handle, extra resources to manage that need to survive across async boundaries. And by asynchronous, I mean either callbacks or manually checked completions from some event system. Modern languages hide that under async/await, which is much better from DX perspective, but still leads to split in the ecosystem, and it's hard to optimize across async boundaries.
This is an example why Go is such a successful language, in my view. It hides the async complexity and allows you to pretend you have a simple continuous thread of execution. It's just cheaper than system threads. Imagine if operating system threads and the blocking syscalls were this efficient.
I've spent the last year building a similar runtime for Zig. Purely because I want my applications to forget they are using things like io_uring in the background.
io_uring has been one of the greatest sources of exploits for the Linux kernel in years. io_uring has resulted in so many practical privilege escalation attacks that many containers completely block it, and companies like Google keep it entirely disabled. RHEL also ships a kernel without it by default.
It got cancelled halfway