Batching syscalls is on my mind. The architecture of Fusion will revolve around channel-based ipc (both sync and async), including between user mode and kernel mode. The end state I'm aiming for is an async channel for syscalls, where the user task issues syscalls, which get buffered in a queue, where the kernel processes the queue asynchronously.
For this to work properly, user tasks need to be able to respond to completed syscalls async as well. That's why my idea of user tasks is that they should be modeled as state machines, with channel-based events as the core mechanism by which code gets executed in a deterministic manner. The equivalent of signals in Unix (which many find one of the bad aspects of Unix design) would be receiving events on one or more channels for various purposes (e.g. IO completion, timers, abort, interrupt, GUI events, etc.).
You might both still be interested in the tiny (EDIT: 27 lines! https://github.com/c-blake/batch/blob/9c7e07670ef1fd0e98687c...) little "virtual machine interpreter" I linked to. Per-interpreter loop overheads are below 100 CPU cycles on several CPUs on a generation of hardware similar to what https://www.usenix.org/system/files/atc20-gu.pdf was mentioning as 700-1000 cycles for microkernel IPC latencies. I'm not sure if the idea coheres with io_uring style dispatch (especially the emphasized polling mode), though.. maybe with some work.
The reason I mentioned it after elcritch's RTOS mention is partly that the way the little interpreter has no backward jumps means there are no loops and so no halting problem issue. So, you can still embed conditional error handling logic in system call batches, but the overall call is bounded by the time of its component calls (that is, if they are bounded, anyway...). That might be a useful property for higher levels of the system to guarantee meeting a real-time budget in many situations with very low complexity. I'm not sure if any of this is original with that github repo, but I haven't seen it before in this specific context.
Perhaps the most complete example of "adding a new sys_batch-based syscall" is https://github.com/c-blake/batch/blob/master/examples/total.... which adds a `mapall` that can mmap a whole file or fail trying (at a couple points) for the purpose of just totaling the bytes as an example calculation.
For this to work properly, user tasks need to be able to respond to completed syscalls async as well. That's why my idea of user tasks is that they should be modeled as state machines, with channel-based events as the core mechanism by which code gets executed in a deterministic manner. The equivalent of signals in Unix (which many find one of the bad aspects of Unix design) would be receiving events on one or more channels for various purposes (e.g. IO completion, timers, abort, interrupt, GUI events, etc.).