Ringbahn: a safe, ergonomic API for io-uring in Rust

栏目: IT技术 · 发布时间: 3年前

内容简介:Inmy previous post, I discussed the new io-uring interface for Linux, and how to create a safe API for using io-uring from Rust. In the time since that post, I have implemented a prototype of such an API. The crate is calledio-uring is going to be majorly

Inmy previous post, I discussed the new io-uring interface for Linux, and how to create a safe API for using io-uring from Rust. In the time since that post, I have implemented a prototype of such an API. The crate is called ringbahn , and it is intended to enable users to perform IO on io-uring without any risk of memory unsafety.

io-uring is going to be majorly important to the development of async IO on Linux in the future, and Linux is the most used platform for the kinds of high performance network services that are a major user of Rust. Rust needs to not only have a solution for using io-uring, but should also have the best solution. Users should be able to easily access the full power of io-uring from ergonomic, memory safe, well abstracted APIs. ringbahn is not production ready, but it is a step toward that goal.

Here’s a code sample, showing how easy it can be to perform IO on ringbahn:

use std::fs::File;
use futures::io::AsyncRead;

use ringbahn::Ring;

async fn read_on_ringbahn(file: File, buf: &mut [u8]) -> io::Result<usize> {
    // the `Ring` adapter takes a std IO object and runs its IO on io-uring
    let mut file: Ring<File> = Ring::new(file);
    file.read(buf).await
}

I hope to write a few posts documenting the internal structure and design of ringbahn.

Events, drivers, and submissions

Ringbahn’s core concept is the Submission future, which allows users to safely run an IO event on an io-uring instance managed by a driver. Submission provides a contract between two types:

  • Events: are IO events (like reads and writes) which can be scheduled on an io-uring instance.
  • Drivers: implement the Drive trait and manage an io-uring instance onto which events can be scheduled.

The Submission type handles the exchange between discrete IO events and the driver that manages the io-uring instance so that the interface is memory safe and straight forward. Once the driver has proffered up space to submit an event, the Submission future manages submitting the event and preparing an internal Completion to wake itself when the event completes.

What is a driver?

One of the most important innovations in ringbahn is the notion of drivers, which manage an io-uring instance. Rather than simply providing an interface to io-uring, ringbahn actually allows end users to replace the default driver and take low-level control over how their IO is scheduled. A driver is responsible for three things:

  • Readying a spot in the submission queue to submit an event. Drivers can apply backpressure if there is not space to submit another event.
  • Submitting all of the prepared events in the submission queue. Again, drivers can apply backpressure here if needed.
  • Processing all of the events in the completion queue so that they will be awoken by passing them to the complete function.

There are many different patterns for implementing drivers and determining how they actually submit events and process their completions. By making this an abstraction point, users will be able to experiment with different driver patterns and benchmark how they perform under different kinds of loads, without rewriting all of the memory-safety aspects themselves.

The current version of ringbahn contains a demo driver which is suitable for testing purposes, but is not the most performant possible implementation. In a future post I’ll explore different designs for driving io-uring and how they could be implemented.

The event contract and ownership lifecycle

On the other side of the contract are event types, which represent a single IO event to be scheduled on the io-uring. The Event trait has an interesting quirk: it contains an unsafe method, Event::prepare .

It’s important to understand what an unsafe methods means : unsafe methods are unsafe to call - meaning that callers must guarantee additional invariants when calling them. However, they are safe to implement (as long as you don’t do anything unsafe inside of them). So when a user implements the Event trait, they are given additional guarantees about how this method will be called that normally they could not assume.

Specifically, they are given a guarantee that after this method is called, the event type will not be accessed again until after the event that’s been prepared is completed or cancelled. In other words, it acts as if Event::prepare “passes ownership” of the event to the kernel. That way, implementers of Event can safely give the kernel ownership of buffers without worrying about them being accessed by other parts of the program.

The Event API also supports a cancellation API, which constructs a “cancellation callback.” At a high level, the concept is this: if a user cancels interest in an event, the cancellation callback is constructed. When the event completes, instead of waking the user’s task (which no longer cares about this event), the cancellation callback is called to clean up any objects the kernel had taken ownership of.

What this means is that the Event API provides a memory-safe abstraction for scheduling IO events which fully supports cancellation without leaking any resources.

The Ring interface and buffer management

The most high-level interface in ringbahn is the Ring type . Inspired by the Async type from smol , it wraps a standard IO object and performs IO on it using io-uring, instead of blocking IO. The Ring type acts like a type that repeatedly submits events to its io-uring driver (internally, it doesn’t use the Submission and Event APIs directly, but the code mirrors those APIs fundamentaly). Ring implements AsyncRead , AsyncWrite , and AsyncBufRead .

Currently, the Ring type submits events using its own managed buffers. However, in the longer term Ring would ideally be abstract over multiple different kinds of buffer management strategies - especially including ones which pre-register buffers with the kernel, which would be the most optimal approach.

Ring will provide a simple and straightforward way to perform async IO using io-uring, and will always be the most accessible, high level API. Users can choose between that and constructing more complex IO patterns using the lower level Event API.

Next steps

Ringbahn is currently just a prototype, which is why I’ve released it to crates.io as 0.0.0-experimental.1 . It contains a lot of unsafe code which has not been sufficiently audited or hardened, and users should not use it in production yet .

In the immediate future, I want to blog in more depth about every aspect of ringbahn’s design. I hope this will help steer the future of Rust’s io-uring support in a productive direction. Expect to see a series of posts on the completion state machine, the driver interface, buffer management, and so forth over the next few weeks.

In the longer term, I would like for there to exist a production ready, best-in-class io-uring interface in Rust. However, I don’t know how much time I will be able to commit to this project, or whether it will continue to be developed over the long term. If anyone is interested in funding this work on a serious basis, I would be interested in hearing from them privately.


以上所述就是小编给大家介绍的《Ringbahn: a safe, ergonomic API for io-uring in Rust》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

中国机器人

中国机器人

[中]王鸿鹏、[中]马娜 / 辽宁人民出版社 / 2017-1-1 / 48.00元

本书对中国机器人领域的发展历史做了引人入胜的介绍,中国机器人成长的过程也是中国经济由弱到强的历程。本书实际是选择了一个独特的视角来解读中国数十年的政治、经济、国家战略问题。中国的未来充满了多重可能性,本书对想了解中国当代与未来发展战略的读者是难得的读本,对智能制造这一当今世界*受关注的高科技领域在战略层面和科技伦理层面进行了深入地剖析和思考,其中提出的诸多前沿性观点是全球都将面对的问题,对中国科学......一起来看看 《中国机器人》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具