Socket
Book a DemoInstallSign in
Socket

a10

Package Overview
Dependencies
Maintainers
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

a10

Source
Cargo
Version
0.2.2
Version published
Maintainers
1
Created
Source

A10

The A10 io_uring library.

This library is meant as a low-level library safely exposing the io_uring API. For simplicity this only has two main types and a number of helper types:

  • Ring is a wrapper around io_uring used to poll for completion events.
  • AsyncFd is a wrapper around a file descriptor that provides a safe API to schedule operations.

Linux Required

Currently this requires a fairly new Linux kernel version, everything should work on Linux v6.1 and up.

Examples

A10 is expected to be integrated into a Future runtime, but it can work as a stand-alone library.

use std::future::Future;
use std::io;
use std::path::PathBuf;

use a10::{AsyncFd, Extract, Ring, SubmissionQueue};

fn main() -> io::Result<()> {
    // Create a new I/O uring supporting 8 submission entries.
    let mut ring = Ring::new(8)?;

    // Get access to the submission queue, used to... well queue submissions.
    let sq = ring.submission_queue().clone();
    // A10 makes use of `Future`s to represent the asynchronous nature of
    // io_uring.
    let future = cat(sq, "./src/lib.rs");

    // This `block_on` function would normally be implement by a `Future`
    // runtime, but we show a simple example implementation below.
    block_on(&mut ring, future)
}

/// A "cat" like function, which reads from `filename` and writes it to
/// standard out.
async fn cat(sq: SubmissionQueue, filename: &str) -> io::Result<()> {
    // Because io_uring uses asychronous operation it needs access to the
    // path for the duration the operation is active. To prevent use-after
    // free and similar issues we need ownership of the arguments. In the
    // case of opening a file it means we need ownership of the file name.
    let filename = PathBuf::from(filename);
    // Open a file for reading.
    let file: AsyncFd = a10::fs::OpenOptions::new().open(sq.clone(), filename).await?;

    // Next we'll read from the from the file.
    // Here we need ownership of the buffer, same reason as discussed above.
    let buf = file.read(Vec::with_capacity(32 * 1024)).await?;

    // Let's write what we read from the file to standard out.
    let stdout = a10::io::stdout(sq);
    // For writing we also need ownership of the buffer, so we move the
    // buffer into function call. However by default we won't get it back,
    // to match the API you see in the standard libray.
    // But using buffers just once it a bit wasteful, so we can it back
    // using the `Extract` trait (the call to `extract`). It changes the
    // return values (and `Future` type) to return the buffer and the amount
    // of bytes written.
    let (buf, n) = stdout.write(buf).extract().await?;

    // All done.
    Ok(())
}

/// Block on the `future`, expecting polling `ring` to drive it forward.
fn block_on<Fut, T>(ring: &mut Ring, future: Fut) -> Fut::Output
where
    Fut: Future<Output = io::Result<T>>,
{
    use std::ptr;
    use std::task::{self, Poll, RawWaker, RawWakerVTable};

    // Pin the future to the stack so we don't move it around.
    let mut future = std::pin::pin!(future);

    // Create a task context to poll the future work.
    let waker = unsafe { task::Waker::from_raw(RawWaker::new(ptr::null(), &WAKER_VTABLE)) };
    let mut ctx = task::Context::from_waker(&waker);

    loop {
        match future.as_mut().poll(&mut ctx) {
            Poll::Ready(result) => return result,
            Poll::Pending => {
                // Poll the `Ring` to get an update on the operation(s).
                //
                // In pratice you would first yield to another future, but
                // in this example we don't have one, so we'll always poll
                // the `Ring`.
                ring.poll(None)?;
            }
        }
    }

    // A waker implementation that does nothing.
    static WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
        |_| RawWaker::new(ptr::null(), &WAKER_VTABLE),
        |_| {},
        |_| {},
        |_| {},
    );
}

For more examples see the examples directory.

FAQs

Package last updated on 17 Aug 2024

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts