NAME

Future::Uring - Future-returning io_uring functions

VERSION

version 0.001

SYNOPSIS

use Future::Uring;
use Future::AsyncAwait;

my $handle = await Future::Uring::open("input.txt");
my $result = await $handle->write($buffer);

DESCRIPTION

NOTE: This module is an early/experimental release, API stability is not guaranteed yet.

This module is an end-user friendly wrapper around Linux' io_uring mechanism. Uring is based on two sets of ring buffers, the submission queue and the completion queue. For every I/O request you need to make (like to read a file, write a file, accept a socket connection, etc), you create a submission queue entry, that describes the I/O operation you need to get done and add it to the tail of the submission queue (SQ). Most functions have the same name name as their synchronous counterparts.

All IO functions take the following optional named parameters (many take additional ones):

  • async

    Normal operation for io_uring is to try and issue a submission as non-blocking first, and if that fails, execute it in an async manner. To support more efficient overlapped operation of requests that the application knows/assumes will always (or most of the time) block, the application can ask for a submission to be issued async from the start. Note that this flag immediately causes the submission event to be offloaded to an async helper thread with no initial non-blocking attempt. This may be less efficient and should not be used liberally or without understanding the performance and efficiency tradeoffs.

  • link

    When this flag is specified, the submission event forms a link with the next submission event in the submission ring. That next submission event will not be started before the previous request completes. This, in effect, forms a chain of submission events, which can be arbitrarily long. The tail of the chain is denoted by the first submission event that does not have this flag set. Chains are not supported across submission boundaries. Even if the last submission event in a submission has this flag set, it will still terminate the current chain. This flag has no effect on previous submission event submissions, nor does it impact submission events that are outside of the chain tail. This means that multiple chains can be executing in parallel, or chains and individual submission events. Only members inside the chain are serialized. A chain of submission events will be broken if any request in that chain ends in error.

  • hardlink

    Like link, except the links aren't severed if an error or unexpected result occurs.

  • drain

    When this flag is specified, the submission event will not be started before previously submitted submission events have completed, and new submission events will not be started before this one completes.

  • timeout

    This adds a link timeout to the request

  • timeout_clock

    This sets the timeout clock. It defaults to monotonic.

  • timeout_absolute

    If set, the passed timeout will not be a relative time

Several functions have two versions, the second one ending in at (e.g. open and openat). In such cases the latter takes an additional directory descriptor as argument for each path argument; this will be used as base instead of the current directory. Passing undef is equivalent to passing it the current directory.

FUNCTIONS

run_once

Future::Uring::run_once($timeout = undef)

This will submit all pending submission events. It will wait for $timeout seconds for events, or indefinitely if it's undefined.

submit

Future::Uring::submit;

This will submit all pending submissions to the kernel.

submissions_available

Future::Uring::submissions_available;

Check the number of available submission queue events. One may need to submit pending entries before creating a chain, because all entries in a linked chains must be submitted together.

to_handle

my $handle = Future::Uring::to_handle($fh)

This takes a Perl handle and turns it into a Future::Uring::Handle.

await Future::Uring::link($old_path, $new_path, %options)
await Future::Uring::linkat($old_dirh, $old_path, $new_dir, $new_path, %options)

This creates a hard link from $new_path to $old_path.

This takes one additional named argument: follow_symlink, if true and $oldpath is a symlink, it will be followed before the operation.

mkdir / mkdirat

await Future::Uring::mkdir($dirname, %options)
await Future::Uring::mkdirat($dirh, $dirname, %options)

Make directory $dirname.

open / openat

my $handle = await Future::Uring::open($filename, $mode = '<', %options);
my $handle = await Future::Uring::openat($dirh, $filename, $mode = '<', %options);

This opens a file, and returns it as a new handle.

This takes several additional options:

  • mode

    The permission mode that will be used if the file is newly created (e.g. 0644).

  • d_sync

    If true, write operations on the file will complete according to the requirements of synchronized I/O data integrity completion.

  • exclusive

    Ensure that this call creates the file: if this flag is specified in conjunction with a creating $mode, and path already exists, then open() fails with the error EEXIST.

  • no_follow

    If the trailing component (i.e., basename) of path is a symbolic link, then the open fails with the error ELOOP. Symbolic links in earlier components of the pathname will still be followed.

  • sync

    If true write operations on the file will complete according to the requirements of synchronized I/O file integrity completion (by contrast with the synchronized I/O data integrity completion provided by d_sync.

  • tempfile

    Create an unnamed temporary regular file. The path argument specifies a directory; an unnamed inode will be created in that directory's filesystem. Anything written to the resulting file will be lost when the last file descriptor is closed, unless the file is given a name.

rename / renameat

await Future::Uring::rename($old_path, $new_path, %options)
await Future::Uring::renameat($old_dirh, $old_path, $new_dirh, $new_path, %options)

Rename the file at $old_path to $new_path.

  • exchange

    Atomically exchange oldpath and newpath. Both pathnames must exist but may be of different types (e.g., one could be a non-empty directory and the other a symbolic link).

  • no_replace

    Don't overwrite newpath of the rename. Return an error if newpath already exists.

rmdir / rmdirat

await Future::Uring::rmdir($dir, %options)
await Future::Uring::rmdirat($dirh, $dir, %options)

socket

my $handle = await Future::Uring::socket($socket, $domain, $type = STREAM_SOCKET, $protocol = 0);

This creates a new handle, taking the same arguments as perl's built-in socket.

timeout_for

await Future::Uring::timeout_for($seconds, %options)

This creates a relative timeout for $seconds. $seconds must either be a number or a Time::Spec object.

It takes one additional named argument: clock, with allowed values are 'monotonic' (default), 'boottime' and 'realtime'.

timeout_until

await Future::Uring::timeout_until($moment, %options)

This creates an absolute timeout for $moment. $moment must either be a number or a Time::Spec object.

It takes one additional named argument: clock, with allowed values are 'monotonic', 'boottime' and 'realtime' (default).

await Future::Uring::unlink($filename, %options)
await Future::Uring::unlinkat($dirh, $filename, %options)

This will unlink the file at $filename.

waitid

await Future::Uring::waitid($type, $id, %options)

This will wait for a child process to terminate. It will return the status as a Signal::Info object. The mechanism of process selection depends on the value of $type.

  • 'pid'

    It will wait for the process whose pid if $id

  • 'pgid'

    It will wait for a child process from process group $id.

  • 'pidfd'

    This will wait for the process behind pidfd $id, which may be a Linux::FD::Pid object instead of a descriptor.

  • 'all'

    This will ignore the value of $id, and will wait for any child.

It takes the following additional named arguments:

  • event

    The type of event what is waited for, it can be any of 'exited' (the default), 'stopped' or 'continued'.

  • nowait

    If true, it will leave the child in a waitable state.

waitpid

await Future::Uring::waitpid($pid, %options)

This is a wrapper of waitid('pid', $pid, %options), except that it will return a conventional exit status instead of a Signal::Info object.

AUTHOR

Leon Timmermans <fawaka@gmail.com>

COPYRIGHT AND LICENSE

This software is copyright (c) 2025 by Leon Timmermans.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.