Skip to content
HN On Hacker News ↗

Ring Buffers Project Summary - Redox

▲ 72 points • 18 comments • by g0xA52A2A • 1w ago • HN discussion ↗

Pangram verdict · v3.3

We believe that this entire text is human-written.

0 %

AI likelihood · overall

Human
100% human-written 0% AI-generated
SEGMENTS · HUMAN 1 of 1
SEGMENTS · AI 0 of 1
WORD COUNT 1,525
PEAK AI % 0% · §1
Analyzed
Oct 31
backend: pangram/v3.3
Segments scanned
1 windows
avg 1525 words each
Distribution
100 / 0%
human / AI fraction
Verdict
Human
Pangram v3.3

Article text · 1,525 words · 1 segments analyzed

Human AI-generated
§1 Human · 0%

By Ibuki Omatsu, Anhad Singh, Jacob Lorentzon, Ron Williams on Sunday, October 25, 2026 Last year, the Redox team received a grant to develop io_uring-like Ring Buffer support at the system task level, as a first step towards ring buffer communications between the application and the majority of system services. This phase of the work finished up in September, as the last pieces were put in place. We want to thank the NLnet Foundation, the NGI Zero Commons Fund, and Horizon Europe for their generous support. The NGI Zero Commons Fund is reaching its end, but NLnet is now accepting applications for grants from new funds, Restack and Code Supply, as well as some smaller theme funds. Apply for funding before November 3rd 2026! (and then every two months after that). The team has done a fantastic job, and I want to congratulate Ibuki, Anhad and Jacob, and thank them for their time and effort. In addition to implementing the Ring Buffer machinery for our system services and drivers that can support it, an io_uring and liburing-like API for applications was completed and demonstrated. There was also substantial work done on support crates, including an async executor for drivers. And there was some very exciting work on various performance improvements, to allow much faster switching between applications and their system services. But I will let the team tell you all the technical details. – Ron Williams Ring Buffers Overview – Anhad Singh Historically asynchronous I/O on Linux was done through the kernel’s native AIO interface. AIO is mainly useful for unbuffered (O_DIRECT) file I/O, and buffered requests silently block1. Developers also raised concerns about its complexity and performance1 2. There is also POSIX AIO, but developers often consider its implementation lackluster and slow1. To address these problems, several alternative asynchronous mechanisms such as fibrils and syslets/threadlets were proposed but were never merged into the mainline Linux kernel. In early 2019, Jens Axboe proposed and developed the io_uring interface, designed to be an efficient, extensible and “easy to use, hard to misuse.” In its early days, io_uring did have a few security issues and memory leaks, but these have since been addressed3. It was merged in Linux 5.1 and is widely used today. The Linux io_uring interface allows the user to submit one or more I/O operations to the kernel, which are then processed in an asynchronous fashion without blocking the userspace process. Redox, being a microkernel, handles I/O in userspace scheme processes rather than in the kernel. Each file description stores a handle to its scheme, so an I/O system call on that file can forward the request to the scheme. The async I/O interface developed in this project, called Redox Rings, uses a mechanism similar to io_uring. However, unlike io_uring which is used to submit operations to the kernel, the Redox Rings interface is used by the application to directly submit requests to the appropriate scheme asynchronously without blocking the application. Additionally, the interface allows I/O requests to be issued without any memory copies, by having a separate shared memory region between the scheme and the application (which can be requested as DMA-capable memory). For portability, the Redox Rings API is designed to be similar to that of liburing and can also be used for general inter-process communication. For example it is used for communication between the RedoxFS filesystem service and NVMed which is the storage driver. The addition of this API has allowed several parts of Redox to reap significant performance improvements! Terminology A ring buffer is a circular queue backed by an array. The interface makes use of two ring buffers which are shared between the application and the scheme: SQ: submission queue, where the application writes requests and the scheme reads them CQ: completion queue, where the scheme writes responses and the application reads them SQE / CQE: submission queue entry / completion queue entry, entries in the SQ and CQ, respectively Buffer pool: A contiguous block of memory, shared between the application and the scheme, from which data buffers are allocated Data buffer: For a request, we currently support a single data buffer, which is a slice of the contiguous buffer pool, defined by an offset and length Since each queue has exactly one producer and consumer, each index is only ever modified by one side. This eliminates the cost of having a shared locking mechanism. The “redox-ring API” – Ibuki Omatsu We’ve introduced the first ring buffer implementation to Redox OS. Unlike Linux’s io_uring, the submission queue (SQ) and completion queue (CQ) are shared exclusively between userspace processes and are never accessed by the kernel. redox-rings is a new crate for ring buffer communication between userspace processes, also providing data structures for FFI use cases. It uses futexes as the main synchronization mechanism, with optional pipe file descriptor support. Based on its FFI support, we’ve introduced the “redox-ring API” in relibc, inspired by Linux’s liburing. liburing is a library for Linux’s io_uring, providing helpers for setting up and tearing down io_uring instances, as well as a simplified interface for submitting I/O requests. Similarly, the redox-ring API allows applications to communicate with daemons that support ring buffers using custom protocols. Key functions The API provides functions for managing ring buffers, shared memory, and requests. redox_ring_queue_init_with_path() initializes a ring buffer connection to a daemon. redox_ring_alloc_buf() and redox_ring_alloc_sized() allocate buffers from the shared memory pool. redox_ring_get_sqe() obtains a submission queue entry (SQE) for preparing a request. redox_ring_submit() submits pending requests to the daemon. redox_ring_wait_cqe() waits for a completion queue entry (CQE), blocking if none is available. redox_ring_cqe_seen() marks a CQE as processed. The API also provides functions for registering file descriptors, freeing allocated buffers, and tearing down ring buffer instances. – Ibuki Omatsu The redox-rings implementation uses shared memory to exchange SQEs, CQEs, and I/O data between applications and daemons. During initialization, the SQ, CQ, and data buffer pool are mapped into the application’s address space using the fmap syscall with MAP_SHARED. This allows both sides to access the same memory without copying I/O data between processes. Buffer allocation The redox-ring API supports two buffer allocation strategies: Fixed-size allocation: Uses a simple allocator that divides the shared memory pool into fixed-size chunks and maintains a list of available offsets. Dynamic allocation: Uses the redox-buffer-pool crate to allocate buffers of varying sizes and alignments. The allocator uses B-trees to manage free and occupied memory regions. Both allocation strategies return a pointer to the allocated buffer and its offset within the shared memory pool. Once an operation has completed, the application can release its buffer, allowing the memory to be reused. Session Creation and Management – Anhad Singh The redox_ring_queue_init_with_path function opens the scheme ring handle and uses the SYS_CALL system call on it to set up the ring buffer session with the given parameters. This returns file descriptors for the SQ, CQ, and shared buffer pool, which are mapped into the application’s address space. The application can then use the queues directly to submit requests and receive completions. On the scheme side, the worker task waits for entries in the SQ, processes them asynchronously and notifies the application on completion. Example: Writing to RamFS – Ibuki Omatsu Ring buffer support was added to RamFS and NVMed. We also added tests that communicate with these storage daemons through the redox-ring API. For example, writing data to RamFS involves the following steps: Open the target file and initialize a ring buffer instance to RamFS using redox_ring_queue_init_with_path(). Register the file descriptor so that subsequent requests can reference it by index. Allocate a shared memory buffer and write the data into it. Obtain an SQE and specify the write operation, file index, buffer offset, data length, and file offset. Submit the prepared SQEs using redox_ring_submit(). Multiple requests can be submitted in a single batch. Wait for CQEs, check the results, and release the buffers associated with completed requests. Once all operations have completed, the application tears down the ring buffer connection. Async Executor – Anhad Singh We developed an async executor for device drivers, with a single interrupt vector and an SQ/CQ pair per core architecture. A single core is used at the moment, and multi-thread-per-core support is in progress. Furthermore, we updated NVMe driver to use the async executor, and more devices such as virtio are expected to follow. With the executor, schemes that support Redox Rings can handle each I/O request in its own async task, with a worker thread spawned for each session between the application and the scheme. On teardown, the worker task is stopped, pending I/O operations are cancelled and shared resources are cleaned up. Figure 1: Comparison between the redox_syscall and redox_ring benchmarks, showing that redox_ring is 14-15x faster. The redox_syscall benchmark performs I/O via synchronous system calls, while the redox_ring benchmark uses the new Redox Ring interface. Kernel and IPC optimizations – Jacob Lorentzon While it has substantially improved over the years, IPC is still quite slow on Redox, and this is important to optimize as ring buffers can only offset this overhead to a certain extent. This has been a focus of our work to improve system performance. Infrastructure