openat-statx-close.dhover×263all
#!/usr/bin/env dub
/+ dub.sdl:
    name "io_uring_openat_statx_close"
    dependency "during" version="~>0.5.0"
    platforms "linux"
    targetPath "build"
+/
/**
 * `io_uring` as a general async-syscall surface — `OPENAT` + `STATX` + `READ` +
 * `CLOSE` (Linux 5.6).
 *
 * Linux 5.6 turned `io_uring` from an I/O-on-already-open-fds engine into a
 * general asynchronous syscall surface: filesystem operations that previously
 * had no async form — opening a path, stat-ing it, closing an fd — became plain
 * SQE opcodes. This example chains the four of them to read a file end to end
 * without ever issuing a synchronous open/stat/read/close:
 *
 *   1. write a known file under `/tmp` synchronously (libc) to have something to open;
 *   2. `OPENAT(AT_FDCWD, path, O_RDONLY)` — the completion's `res` is the new fd;
 *   3. `STATX(fd, "", AT_EMPTY_PATH, STATX_SIZE)` — verify the file size;
 *   4. `READ(fd, buf, 0)` — verify the bytes round-trip;
 *   5. `CLOSE(fd)` — release it through the ring.
 *
 * Each step is its own submit/wait: `OPENAT`'s result fd is the input to the
 * following ops, so they cannot be batched into one independent submission.
 *
 * Companion to the io_uring chronology:
 * see docs/research/async-io/io-uring/timeline.md
 * § "5.6 — The filesystem/syscall expansion (March 2020)".
 *
 * Run with: `dub run --single openat-statx-close.d`
 *
 * Portability: prints a `SKIP:` line and exits 0 when `io_uring` is unavailable
 * (old kernel / sandbox) or when any of these 5.6 ops is unsupported, so it stays
 * green in CI regardless of the host kernel.
 */
module 
(module) io_uring_openat_statx_close

io_uring as a general async-syscall surface — OPENAT + STATX + READ + CLOSE (Linux 5.6).

Linux 5.6 turned io_uring from an I/O-on-already-open-fds engine into a general asynchronous syscall surface: filesystem operations that previously had no async form — opening a path, stat-ing it, closing an fd — became plain SQE opcodes. This example chains the four of them to read a file end to end without ever issuing a synchronous open/stat/read/close:

  1. write a known file under /tmp synchronously (libc) to have something to open;

  2. OPENAT(AT_FDCWD, path, O_RDONLY) — the completion's res is the new fd;

  3. STATX(fd, "", AT_EMPTY_PATH, STATX_SIZE) — verify the file size;

  4. READ(fd, buf, 0) — verify the bytes round-trip;

  5. CLOSE(fd) — release it through the ring.

Each step is its own submit/wait: OPENAT's result fd is the input to the following ops, so they cannot be batched into one independent submission.

Companion to the io_uring chronology: see docs/research/async-io/io-uring/timeline.md § "5.6 — The filesystem/syscall expansion (March 2020)".

Run with: dub run --single openat-statx-close.d

Portability

prints a SKIP: line and exits 0 when io_uring is unavailable (old kernel / sandbox) or when any of these 5.6 ops is unsupported, so it stays green in CI regardless of the host kernel.

io_uring_openat_statx_close
;
import
(module) during

Simple idiomatic dlang wrapper around linux io_uring (see: https://kernel.dk/io_uring.pdf) asynchronous API.

during
;
import
(package) core
core
.
(package) core.sys
sys
.
(package) core.sys.posix
posix
.
(module) core.sys.posix.fcntl

D header file for POSIX.

@copyrightCopyright Sean Kelly 2005 - 2009.@licenseBoost License 1.0.@authorsSean Kelly, Alex Rønne Petersen@standardsThe Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition
fcntl
:
(alias constant) io_uring_openat_statx_close.AT_FDCWD = int core.sys.posix.fcntl.AT_FDCWD = -100
AT_FDCWD
,
(alias constant) io_uring_openat_statx_close.O_CREAT = int core.sys.posix.fcntl.O_CREAT = 64
O_CREAT
,
(alias constant) io_uring_openat_statx_close.O_RDONLY = int core.sys.posix.fcntl.O_RDONLY = 0
O_RDONLY
,
(alias constant) io_uring_openat_statx_close.O_WRONLY = int core.sys.posix.fcntl.O_WRONLY = 1
O_WRONLY
, open;
import
(package) core
core
.
(package) core.sys
sys
.
(package) core.sys.posix
posix
.
(module) core.sys.posix.unistd

D header file for POSIX.

@copyrightCopyright Sean Kelly 2005 - 2009.@licenseBoost License 1.0.@authorsSean Kelly@standardsThe Open Group Base Specifications Issue 8, IEEE Std 1003.1, 2024 Edition
unistd
:
(alias) io_uring_openat_statx_close.close = int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
,
(alias) io_uring_openat_statx_close.unlink = int core.sys.posix.unistd.unlink(scope const(char*)) nothrow @nogc
unlink
,
(alias) io_uring_openat_statx_close.write = long core.sys.posix.unistd.write(int, scope const(void*), ulong) nothrow @nogc
write
;
import
(package) std
std
.
(module) std.stdio
Category Symbols
File handles _popen File isFileHandle openNetwork stderr stdin stdout
Reading chunks lines readf readfln readln
Writing toFile write writef writefln writeln
Misc KeepTerminator LockType StdioException

Standard I/O functions that extend core.stdc.stdio. core.stdc.stdio is publically imported when importing std.stdio.

There are three layers of I/O:

  1. The lowest layer is the operating system layer. The two main schemes are Windows and Posix.

  2. C's stdio.h which unifies the two operating system schemes.

  3. std.stdio, this module, unifies the various stdio.h implementations into a high level package for D programs.

Source

std/stdio.d

@copyrightCopyright The D Language Foundation 2007-.@licenseBoost License 1.0.@authorsWalter Bright, Andrei Alexandrescu, Alex Rønne Petersen
stdio
: stderr,
(alias template) io_uring_openat_statx_close.writefln = std.stdio.writefln(alias fmt, A...)(A args) if (isSomeString!(typeof(fmt)))

Equivalent to writef(fmt, args, '\n').

writefln
;
import
(package) std
std
.
(module) std.string

String handling functions.

Category Functions
Searching
column
indexOf
indexOfAny
indexOfNeither
lastIndexOf
lastIndexOfAny
lastIndexOfNeither
Comparison
isNumeric
Mutation
capitalize
Pruning and Filling
center
chomp
chompPrefix
chop
detabber
detab
entab
entabber
leftJustify
outdent
rightJustify
strip
stripLeft
stripRight
wrap
Substitution
abbrev
soundex
soundexer
succ
tr
translate
Miscellaneous
assumeUTF
fromStringz
lineSplitter
representation
splitLines
toStringz
Objects of types string, wstring, and dstring are value types
and cannot be mutated element-by-element. For using mutation during building
strings, use char[], wchar[], or dchar[]. The xxxstring
types are preferable because they don't exhibit undesired aliasing, thus
making code more robust.

The following functions are publicly imported:

Module Functions
Publicly imported functions
std.algorithm
cmp, std,algorithm,comparison
count, std,algorithm,searching
endsWith, std,algorithm,searching
startsWith, std,algorithm,searching
std.array
join, std,array
replace, std,array
replaceInPlace, std,array
split, std,array
empty, std,array
std.format
format, std,format
sformat, std,format
std.uni
icmp, std,uni
toLower, std,uni
toLowerInPlace, std,uni
toUpper, std,uni
toUpperInPlace, std,uni
There is a rich set of functions for string handling defined in other modules.
Functions related to Unicode and ASCII are found in std.uni
and std.ascii, respectively. Other functions that have a
wider generality than just strings can be found in std.algorithm
and std.range.

Source

std/string.d

@seestd.algorithm and std.range for generic range algorithms , std.ascii for functions that work with ASCII strings , std.uni for functions that work with unicode strings@copyrightCopyright The D Language Foundation 2007-.@licenseBoost License 1.0.@authorsWalter Bright, Andrei Alexandrescu, Jonathan M Davis, and David L. 'SpottedTiger' Davis
string
:
(alias) io_uring_openat_statx_close.toStringz = immutable(char)* std.string.toStringz(scope const(char)[] s) pure nothrow @trusted
@params A D-style string.@returns

A C-style null-terminated string equivalent to s. s must not contain embedded '\0''s as any C function will treat the first '\0' that it sees as the end of the string. If s.empty is true, then a string containing only '\0' is returned.

Important Note: When passing a char* to a C function, and the C function keeps it around for any reason, make sure that you keep a reference to it in your D code. Otherwise, it may become invalid during a garbage collection cycle and cause a nasty bug when the C code tries to use it.

toStringz
;
// ABI-stable constants the kernel uses but druntime does not surface here. enum int
(constant) int io_uring_openat_statx_close.AT_EMPTY_PATH = 4096
AT_EMPTY_PATH
= 0x1000; // statx() on an open fd with an empty path
enum uint
(constant) uint io_uring_openat_statx_close.STATX_SIZE = 512u
STATX_SIZE
= 0x0000_0200; // request stx_size in the result mask
// Minimal mirror of the kernel `struct statx` (256 bytes, ABI-stable). We only // read `stx_size`, which lives at byte offset 40; the rest is padding we never // touch. `prepStatx` takes the buffer generically, so any 256-byte struct with // the field at the right offset works. struct
(struct) io_uring_openat_statx_close.Statx
Statx
{ uint
(field) uint io_uring_openat_statx_close.Statx.stx_mask
stx_mask
; // 0
uint
(field) uint io_uring_openat_statx_close.Statx.stx_blksize
stx_blksize
; // 4
ulong
(field) ulong io_uring_openat_statx_close.Statx.stx_attributes
stx_attributes
; // 8
uint
(field) uint io_uring_openat_statx_close.Statx.stx_nlink
stx_nlink
; // 16
uint
(field) uint io_uring_openat_statx_close.Statx.stx_uid
stx_uid
; // 20
uint
(field) uint io_uring_openat_statx_close.Statx.stx_gid
stx_gid
; // 24
ushort
(field) ushort io_uring_openat_statx_close.Statx.stx_mode
stx_mode
; // 28
ushort[1]
(field) ushort[1] io_uring_openat_statx_close.Statx._spare0
_spare0
; // 30
ulong
(field) ulong io_uring_openat_statx_close.Statx.stx_ino
stx_ino
; // 32
ulong
(field) ulong io_uring_openat_statx_close.Statx.stx_size
stx_size
; // 40 -- the only field we assert on
ubyte[256 - 48]
(field) ubyte[208] io_uring_openat_statx_close.Statx._rest
_rest
; // 48.. -- timestamps, dev numbers, future fields
} static assert(
(struct) io_uring_openat_statx_close.Statx
Statx
.
(field) ulong io_uring_openat_statx_close.Statx.stx_size
stx_size
.offsetof == 40, "stx_size must sit at the kernel ABI offset");
static assert(
(struct) io_uring_openat_statx_close.Statx
Statx
.sizeof >= 256, "statx buffer must cover the full kernel struct");
int
int D main()
main
()
{ // The file we will open/stat/read through the ring. enum
(alias) object.string = string
string
(constant) string io_uring_openat_statx_close.main.path = "/tmp/io_uring_openat_statx_close.txt"
path
= "/tmp/io_uring_openat_statx_close.txt";
immutable(ubyte)[]
(local variable) immutable(ubyte)[] payload
payload
= cast(immutable(ubyte)[]) "io_uring touched the filesystem\n";
// --- Step 1: create the test file synchronously (plain libc). ----------- { const
(local variable) const(int) wfd
wfd
= open(
int core.sys.posix.fcntl.open64(scope const(char*), int, ...) nothrow @nogc
path
.
immutable(char)* std.string.toStringz(scope const(char)[] s) pure nothrow @trusted

Examples

import core.stdc.string : strlen;
import std.conv : to;

auto p = toStringz("foo");
assert(strlen(p) == 3);
const(char)[] foo = "abbzxyzzy";
p = toStringz(foo[3 .. 5]);
assert(strlen(p) == 2);

string test = "";
p = toStringz(test);
assert(*p == 0);

test = "\0";
p = toStringz(test);
assert(*p == 0);

test = "foo\0";
p = toStringz(test);
assert(p[0] == 'f' && p[1] == 'o' && p[2] == 'o' && p[3] == 0);

const string test2 = "";
p = toStringz(test2);
assert(*p == 0);

assert(toStringz([]) is toStringz(""));
@params A D-style string.@returns

A C-style null-terminated string equivalent to s. s must not contain embedded '\0''s as any C function will treat the first '\0' that it sees as the end of the string. If ``s.empty is true, then a string containing only '\0' is returned.

Important Note: When passing a char* to a C function, and the C function keeps it around for any reason, make sure that you keep a reference to it in your D code. Otherwise, it may become invalid during a garbage collection cycle and cause a nasty bug when the C code tries to use it.

toStringz
,
(constant) int core.sys.posix.fcntl.O_CREAT = 64
O_CREAT
|
(constant) int core.sys.posix.fcntl.O_WRONLY = 1
O_WRONLY
,
(template instance) io_uring_openat_statx_close.octal!"600"
octal
!"600");
if (
(local variable) const(int) wfd
wfd
< 0)
{
void std.stdio.writefln!(char, string, int)(in char[] fmt, string __param_1, int __param_2) @safe

Equivalent to writef(fmt, args, '\n').

writefln
("SKIP: could not create %s (errno %d)",
(constant) string io_uring_openat_statx_close.main.path = "/tmp/io_uring_openat_statx_close.txt"
path
,
int io_uring_openat_statx_close.errnoOf(int ret) pure nothrow @nogc @safe
errnoOf
(
(local variable) const(int) wfd
wfd
));
return 0; } const
(local variable) const(long) wrote
wrote
=
long core.sys.posix.unistd.write(int, scope const(void*), ulong) nothrow @nogc
write
(
(local variable) const(int) wfd
wfd
,
(local variable) immutable(ubyte)[] payload
payload
.
(field) immutable(ubyte)* immutable(ubyte)[].ptr
ptr
,
(local variable) immutable(ubyte)[] payload
payload
.
(field) ulong immutable(ubyte)[].length
length
);
int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
(
(local variable) const(int) wfd
wfd
);
if (
(local variable) const(long) wrote
wrote
!=
(local variable) immutable(ubyte)[] payload
payload
.
(field) ulong immutable(ubyte)[].length
length
)
{ stderr.
std.stdio.File std.stdio.makeGlobal!"core.stdc.stdio.stderr"() nothrow @nogc @property ref @system
writefln
("setup write short: %d of %d bytes",
(local variable) const(long) wrote
wrote
,
(local variable) immutable(ubyte)[] payload
payload
.
(field) ulong immutable(ubyte)[].length
length
);
return 1; } } scope (exit)
int core.sys.posix.unistd.unlink(scope const(char*)) nothrow @nogc
unlink
(
(constant) string io_uring_openat_statx_close.main.path = "/tmp/io_uring_openat_statx_close.txt"
path
.
immutable(char)* std.string.toStringz(scope const(char)[] s) pure nothrow @trusted

Examples

import core.stdc.string : strlen;
import std.conv : to;

auto p = toStringz("foo");
assert(strlen(p) == 3);
const(char)[] foo = "abbzxyzzy";
p = toStringz(foo[3 .. 5]);
assert(strlen(p) == 2);

string test = "";
p = toStringz(test);
assert(*p == 0);

test = "\0";
p = toStringz(test);
assert(*p == 0);

test = "foo\0";
p = toStringz(test);
assert(p[0] == 'f' && p[1] == 'o' && p[2] == 'o' && p[3] == 0);

const string test2 = "";
p = toStringz(test2);
assert(*p == 0);

assert(toStringz([]) is toStringz(""));
@params A D-style string.@returns

A C-style null-terminated string equivalent to s. s must not contain embedded '\0''s as any C function will treat the first '\0' that it sees as the end of the string. If ``s.empty is true, then a string containing only '\0' is returned.

Important Note: When passing a char* to a C function, and the C function keeps it around for any reason, make sure that you keep a reference to it in your D code. Otherwise, it may become invalid during a garbage collection cycle and cause a nasty bug when the C code tries to use it.

toStringz
);
// --- Ring setup. --------------------------------------------------------
(struct) during.Uring

Main entry point to work with io_uring.

It hides SubmissionQueue and CompletionQueue behind standard range interface. We put in SubmissionEntry entries and take out CompletionEntry entries.

Use predefined prepXX methods to fill required fields of SubmissionEntry before put or during putWith.

Note

prepXX functions doesn't touch previous entry state, just fills in operation properties. This is because for less error prone interface it is cleared automatically when prepared using putWith. So when using on own SubmissionEntry (outside submission queue), that would be added to the submission queue using put, be sure its cleared if it's reused for multiple operations.

Uring
(local variable) during.Uring io
io
;
const
(local variable) const(int) setupRet
setupRet
=
(local variable) during.Uring io
io
.
int during.setup(ref during.Uring uring, uint entries = 128u, during.io_uring.SetupFlags flags = SetupFlags.NONE) nothrow @nogc @safe

Setup new instance of io_uring into provided Uring structure.

@paramuring Uring structure to be initialized (must not be already initialized)@paramentries Number of entries to initialize uring with@paramflags SetupFlags to use to initialize uring.@returnsOn succes it returns 0, -errno otherwise.
setup
(8);
if (
(local variable) const(int) setupRet
setupRet
< 0)
{
void std.stdio.writefln!(char, const(int))(in char[] fmt, const(int) __param_1) @safe

Equivalent to writef(fmt, args, '\n').

writefln
("SKIP: io_uring_setup failed (errno %d) — io_uring unavailable on this host", -
(local variable) const(int) setupRet
setupRet
);
return 0; } // The filesystem ops all arrived together in 5.6; probe one representative // op up front so a pre-5.6 kernel skips cleanly rather than erroring mid-chain. auto
(local variable) during.Probe probe
probe
=
(local variable) during.Uring io
io
.
during.Probe during.Uring.probe() nothrow @nogc @safe

Probes supported operations

probe
();
if (cast(bool)
(local variable) during.Probe probe
probe
&& !
(local variable) during.Probe probe
probe
.
bool during.Probe.isSupported(during.io_uring.Operation op) const pure nothrow @nogc @safe

Is operation supported?

isSupported
(
(enum) during.io_uring.Operation

Describes the operation to be performed

@seeio_uring_enter(2)
Operation
.
(enum value) during.io_uring.Operation.OPENAT = cast(ubyte)18u

IORING_OP_OPENAT

OPENAT
))
{
void std.stdio.writefln!char(in char[] fmt) @safe

Equivalent to writef(fmt, args, '\n').

writefln
("SKIP: IORING_OP_OPENAT unsupported on this kernel (pre-5.6)");
return 0; } // --- Step 2: OPENAT — the completion res is the freshly opened fd. ------ auto
(local variable) immutable(char)* cpath
cpath
=
(constant) string io_uring_openat_statx_close.main.path = "/tmp/io_uring_openat_statx_close.txt"
path
.
immutable(char)* std.string.toStringz(scope const(char)[] s) pure nothrow @trusted

Examples

import core.stdc.string : strlen;
import std.conv : to;

auto p = toStringz("foo");
assert(strlen(p) == 3);
const(char)[] foo = "abbzxyzzy";
p = toStringz(foo[3 .. 5]);
assert(strlen(p) == 2);

string test = "";
p = toStringz(test);
assert(*p == 0);

test = "\0";
p = toStringz(test);
assert(*p == 0);

test = "foo\0";
p = toStringz(test);
assert(p[0] == 'f' && p[1] == 'o' && p[2] == 'o' && p[3] == 0);

const string test2 = "";
p = toStringz(test2);
assert(*p == 0);

assert(toStringz([]) is toStringz(""));
@params A D-style string.@returns

A C-style null-terminated string equivalent to s. s must not contain embedded '\0''s as any C function will treat the first '\0' that it sees as the end of the string. If ``s.empty is true, then a string containing only '\0' is returned.

Important Note: When passing a char* to a C function, and the C function keeps it around for any reason, make sure that you keep a reference to it in your D code. Otherwise, it may become invalid during a garbage collection cycle and cause a nasty bug when the C code tries to use it.

toStringz
; // keep the C string alive across the submit
(local variable) during.Uring io
io
.putWith!((ref SubmissionEntry e, const(char)* p) {
e.prepOpenat(AT_FDCWD, p, O_RDONLY, 0); e.user_data = 1; })(
during.Uring during.Uring.putWith!(function (ref during.io_uring.SubmissionEntry e, const(char)* p) nothrow @nogc @system { prepOpenat(e, -100, p, 0, 0u); e.user_data = 1LU; } , immutable(char)*)(ref immutable(char)* __param_0) nothrow @nogc return ref @safe

Adds new entry to the SubmissionQueue.

Note that this just adds entry to the queue and doesn't advance the tail marker kernel sees. For that finishSq() is needed to be called next.

Also note that to actually enter new entries to kernel, it's needed to call submit().

@paramFN Function to fill next entry in queue by ref (should be faster). It is expected to be in a form of void function(ARGS)(ref SubmissionEntry, auto ref ARGS). Note that in this case queue entry is cleaned first before function is called.@paramentry Custom built SubmissionEntry to be posted as is. Note that in this case it is copied whole over one in the SubmissionQueue.@paramargs Optional arguments passed to the function@returnsreference to Uring structure so it's possible to chain multiple commands.
cpath
);
if (
(local variable) during.Uring io
io
.
int during.Uring.submit(uint want) nothrow @nogc @safe

Submits qued SubmissionEntry to be processed by kernel.

@paramwant number of CompletionEntries to wait for. If 0, this just submits queued entries and returns. If > 0, it blocks until at least wanted number of entries were completed.@paramsig See io_uring_enter(2) man page@returnsNumber of submitted entries on success, -errno on error
submit
(1) < 0)
return
int io_uring_openat_statx_close.fail(string what)
fail
("submit OPENAT");
(local variable) during.Uring io
io
.
int during.Uring.wait(uint want = 1u) nothrow @nogc

Simmilar to submit but with this method we just wait for required number of CompletionEntries.

@returns0 on success, -errno on error
wait
(1);
const
(local variable) const(int) openRes
openRes
=
(local variable) during.Uring io
io
.
during.io_uring.CompletionEntry during.Uring.front() pure nothrow @nogc return ref @safe

Get first CompletionEntry from cq ring

front
.
(field) int during.io_uring.CompletionEntry.res

result code for this event

res
;
(local variable) during.Uring io
io
.
void during.Uring.popFront() pure nothrow @nogc @safe

Move to next CompletionEntry

popFront
();
if (
bool io_uring_openat_statx_close.isUnsupported(int res) pure nothrow @nogc @safe
isUnsupported
(
(local variable) const(int) openRes
openRes
))
{
void std.stdio.writefln!(char, const(int))(in char[] fmt, const(int) __param_1) @safe

Equivalent to writef(fmt, args, '\n').

writefln
("SKIP: OPENAT returned %d (op unsupported on this kernel)",
(local variable) const(int) openRes
openRes
);
return 0; } if (
(local variable) const(int) openRes
openRes
< 0)
return
int io_uring_openat_statx_close.failErr(string op, int res)
failErr
("OPENAT",
(local variable) const(int) openRes
openRes
);
const
(local variable) const(int) fd
fd
=
(local variable) const(int) openRes
openRes
; // the async-opened fd, used by the next ops
// From here a failure leaks the fd unless we close it; do that on any early return. scope (failure)
int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
(
(local variable) const(int) fd
fd
);
// --- Step 3: STATX on the open fd (empty path + AT_EMPTY_PATH). ---------
(struct) io_uring_openat_statx_close.Statx
Statx
(local variable) io_uring_openat_statx_close.Statx stx
stx
;
(local variable) during.Uring io
io
.putWith!((ref SubmissionEntry e, int f, Statx* sb) {
// Empty path + AT_EMPTY_PATH means "stat the fd itself", like fstat(). e.prepStatx(f, emptyCString, AT_EMPTY_PATH, STATX_SIZE, *sb); e.user_data = 2; })(
during.Uring during.Uring.putWith!(function (ref during.io_uring.SubmissionEntry e, int f, io_uring_openat_statx_close.Statx* sb) nothrow @nogc @system { prepStatx(e, f, emptyCString(), 4096, 512u, *sb); e.user_data = 2LU; } , const(int), io_uring_openat_statx_close.Statx*)(ref const(int) __param_0, io_uring_openat_statx_close.Statx* __param_1) nothrow @nogc return ref @safe

Adds new entry to the SubmissionQueue.

Note that this just adds entry to the queue and doesn't advance the tail marker kernel sees. For that finishSq() is needed to be called next.

Also note that to actually enter new entries to kernel, it's needed to call submit().

@paramFN Function to fill next entry in queue by ref (should be faster). It is expected to be in a form of void function(ARGS)(ref SubmissionEntry, auto ref ARGS). Note that in this case queue entry is cleaned first before function is called.@paramentry Custom built SubmissionEntry to be posted as is. Note that in this case it is copied whole over one in the SubmissionQueue.@paramargs Optional arguments passed to the function@returnsreference to Uring structure so it's possible to chain multiple commands.
fd
, &
during.Uring during.Uring.putWith!(function (ref during.io_uring.SubmissionEntry e, int f, io_uring_openat_statx_close.Statx* sb) nothrow @nogc @system { prepStatx(e, f, emptyCString(), 4096, 512u, *sb); e.user_data = 2LU; } , const(int), io_uring_openat_statx_close.Statx*)(ref const(int) __param_0, io_uring_openat_statx_close.Statx* __param_1) nothrow @nogc return ref @safe

Adds new entry to the SubmissionQueue.

Note that this just adds entry to the queue and doesn't advance the tail marker kernel sees. For that finishSq() is needed to be called next.

Also note that to actually enter new entries to kernel, it's needed to call submit().

@paramFN Function to fill next entry in queue by ref (should be faster). It is expected to be in a form of void function(ARGS)(ref SubmissionEntry, auto ref ARGS). Note that in this case queue entry is cleaned first before function is called.@paramentry Custom built SubmissionEntry to be posted as is. Note that in this case it is copied whole over one in the SubmissionQueue.@paramargs Optional arguments passed to the function@returnsreference to Uring structure so it's possible to chain multiple commands.
stx
);
if (
(local variable) during.Uring io
io
.
int during.Uring.submit(uint want) nothrow @nogc @safe

Submits qued SubmissionEntry to be processed by kernel.

@paramwant number of CompletionEntries to wait for. If 0, this just submits queued entries and returns. If > 0, it blocks until at least wanted number of entries were completed.@paramsig See io_uring_enter(2) man page@returnsNumber of submitted entries on success, -errno on error
submit
(1) < 0)
return
int io_uring_openat_statx_close.failClose(int fd, string what)
failClose
(
(local variable) const(int) fd
fd
, "submit STATX");
(local variable) during.Uring io
io
.
int during.Uring.wait(uint want = 1u) nothrow @nogc

Simmilar to submit but with this method we just wait for required number of CompletionEntries.

@returns0 on success, -errno on error
wait
(1);
const
(local variable) const(int) statxRes
statxRes
=
(local variable) during.Uring io
io
.
during.io_uring.CompletionEntry during.Uring.front() pure nothrow @nogc return ref @safe

Get first CompletionEntry from cq ring

front
.
(field) int during.io_uring.CompletionEntry.res

result code for this event

res
;
(local variable) during.Uring io
io
.
void during.Uring.popFront() pure nothrow @nogc @safe

Move to next CompletionEntry

popFront
();
if (
bool io_uring_openat_statx_close.isUnsupported(int res) pure nothrow @nogc @safe
isUnsupported
(
(local variable) const(int) statxRes
statxRes
))
{
int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
(
(local variable) const(int) fd
fd
);
void std.stdio.writefln!(char, const(int))(in char[] fmt, const(int) __param_1) @safe

Equivalent to writef(fmt, args, '\n').

writefln
("SKIP: STATX returned %d (op unsupported on this kernel)",
(local variable) const(int) statxRes
statxRes
);
return 0; } if (
(local variable) const(int) statxRes
statxRes
< 0)
{
int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
(
(local variable) const(int) fd
fd
);
return
int io_uring_openat_statx_close.failErr(string op, int res)
failErr
("STATX",
(local variable) const(int) statxRes
statxRes
);
} if (
(local variable) io_uring_openat_statx_close.Statx stx
stx
.
(field) ulong io_uring_openat_statx_close.Statx.stx_size
stx_size
!=
(local variable) immutable(ubyte)[] payload
payload
.
(field) ulong immutable(ubyte)[].length
length
)
{
int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
(
(local variable) const(int) fd
fd
);
stderr.
std.stdio.File std.stdio.makeGlobal!"core.stdc.stdio.stderr"() nothrow @nogc @property ref @system
writefln
("STATX size mismatch: expected %d, got %d",
(local variable) immutable(ubyte)[] payload
payload
.
(field) ulong immutable(ubyte)[].length
length
,
(local variable) io_uring_openat_statx_close.Statx stx
stx
.
(field) ulong io_uring_openat_statx_close.Statx.stx_size
stx_size
);
return 1; } // --- Step 4: READ the whole file through the ring and verify content. --- ubyte[128]
(local variable) ubyte[128] readBuf
readBuf
;
(local variable) during.Uring io
io
.putWith!((ref SubmissionEntry e, int f, ubyte[] b) {
e.prepRead(f, b, 0); e.user_data = 3; })(
during.Uring during.Uring.putWith!(function (ref during.io_uring.SubmissionEntry e, int f, ubyte[] b) nothrow @nogc @safe { prepRead(e, f, b, 0L); e.user_data = 3LU; } , const(int), ubyte[])(ref const(int) __param_0, ubyte[] __param_1) nothrow @nogc return ref @safe

Adds new entry to the SubmissionQueue.

Note that this just adds entry to the queue and doesn't advance the tail marker kernel sees. For that finishSq() is needed to be called next.

Also note that to actually enter new entries to kernel, it's needed to call submit().

@paramFN Function to fill next entry in queue by ref (should be faster). It is expected to be in a form of void function(ARGS)(ref SubmissionEntry, auto ref ARGS). Note that in this case queue entry is cleaned first before function is called.@paramentry Custom built SubmissionEntry to be posted as is. Note that in this case it is copied whole over one in the SubmissionQueue.@paramargs Optional arguments passed to the function@returnsreference to Uring structure so it's possible to chain multiple commands.
fd
,
during.Uring during.Uring.putWith!(function (ref during.io_uring.SubmissionEntry e, int f, ubyte[] b) nothrow @nogc @safe { prepRead(e, f, b, 0L); e.user_data = 3LU; } , const(int), ubyte[])(ref const(int) __param_0, ubyte[] __param_1) nothrow @nogc return ref @safe

Adds new entry to the SubmissionQueue.

Note that this just adds entry to the queue and doesn't advance the tail marker kernel sees. For that finishSq() is needed to be called next.

Also note that to actually enter new entries to kernel, it's needed to call submit().

@paramFN Function to fill next entry in queue by ref (should be faster). It is expected to be in a form of void function(ARGS)(ref SubmissionEntry, auto ref ARGS). Note that in this case queue entry is cleaned first before function is called.@paramentry Custom built SubmissionEntry to be posted as is. Note that in this case it is copied whole over one in the SubmissionQueue.@paramargs Optional arguments passed to the function@returnsreference to Uring structure so it's possible to chain multiple commands.
readBuf
[]);
if (
(local variable) during.Uring io
io
.
int during.Uring.submit(uint want) nothrow @nogc @safe

Submits qued SubmissionEntry to be processed by kernel.

@paramwant number of CompletionEntries to wait for. If 0, this just submits queued entries and returns. If > 0, it blocks until at least wanted number of entries were completed.@paramsig See io_uring_enter(2) man page@returnsNumber of submitted entries on success, -errno on error
submit
(1) < 0)
return
int io_uring_openat_statx_close.failClose(int fd, string what)
failClose
(
(local variable) const(int) fd
fd
, "submit READ");
(local variable) during.Uring io
io
.
int during.Uring.wait(uint want = 1u) nothrow @nogc

Simmilar to submit but with this method we just wait for required number of CompletionEntries.

@returns0 on success, -errno on error
wait
(1);
const
(local variable) const(int) readRes
readRes
=
(local variable) during.Uring io
io
.
during.io_uring.CompletionEntry during.Uring.front() pure nothrow @nogc return ref @safe

Get first CompletionEntry from cq ring

front
.
(field) int during.io_uring.CompletionEntry.res

result code for this event

res
;
(local variable) during.Uring io
io
.
void during.Uring.popFront() pure nothrow @nogc @safe

Move to next CompletionEntry

popFront
();
if (
(local variable) const(int) readRes
readRes
< 0)
{
int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
(
(local variable) const(int) fd
fd
);
return
int io_uring_openat_statx_close.failErr(string op, int res)
failErr
("READ",
(local variable) const(int) readRes
readRes
);
} if (
(local variable) const(int) readRes
readRes
!= cast(int)
(local variable) immutable(ubyte)[] payload
payload
.
(field) ulong immutable(ubyte)[].length
length
||
(local variable) ubyte[128] readBuf
readBuf
[0 ..
(local variable) immutable(ubyte)[] payload
payload
.
(field) ulong immutable(ubyte)[].length
length
] !=
(local variable) immutable(ubyte)[] payload
payload
[])
{
int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
(
(local variable) const(int) fd
fd
);
stderr.
std.stdio.File std.stdio.makeGlobal!"core.stdc.stdio.stderr"() nothrow @nogc @property ref @system
writefln
("READ content mismatch (res=%d)",
(local variable) const(int) readRes
readRes
);
return 1; } // --- Step 5: CLOSE the fd through the ring (no scope guard hereafter). ---
(local variable) during.Uring io
io
.putWith!((ref SubmissionEntry e, int f) {
e.prepClose(f); e.user_data = 4; })(
during.Uring during.Uring.putWith!(function (ref during.io_uring.SubmissionEntry e, int f) nothrow @nogc @safe { prepClose(e, f); e.user_data = 4LU; } , const(int))(ref const(int) __param_0) nothrow @nogc return ref @safe

Adds new entry to the SubmissionQueue.

Note that this just adds entry to the queue and doesn't advance the tail marker kernel sees. For that finishSq() is needed to be called next.

Also note that to actually enter new entries to kernel, it's needed to call submit().

@paramFN Function to fill next entry in queue by ref (should be faster). It is expected to be in a form of void function(ARGS)(ref SubmissionEntry, auto ref ARGS). Note that in this case queue entry is cleaned first before function is called.@paramentry Custom built SubmissionEntry to be posted as is. Note that in this case it is copied whole over one in the SubmissionQueue.@paramargs Optional arguments passed to the function@returnsreference to Uring structure so it's possible to chain multiple commands.
fd
);
if (
(local variable) during.Uring io
io
.
int during.Uring.submit(uint want) nothrow @nogc @safe

Submits qued SubmissionEntry to be processed by kernel.

@paramwant number of CompletionEntries to wait for. If 0, this just submits queued entries and returns. If > 0, it blocks until at least wanted number of entries were completed.@paramsig See io_uring_enter(2) man page@returnsNumber of submitted entries on success, -errno on error
submit
(1) < 0)
return
int io_uring_openat_statx_close.failClose(int fd, string what)
failClose
(
(local variable) const(int) fd
fd
, "submit CLOSE");
(local variable) during.Uring io
io
.
int during.Uring.wait(uint want = 1u) nothrow @nogc

Simmilar to submit but with this method we just wait for required number of CompletionEntries.

@returns0 on success, -errno on error
wait
(1);
const
(local variable) const(int) closeRes
closeRes
=
(local variable) during.Uring io
io
.
during.io_uring.CompletionEntry during.Uring.front() pure nothrow @nogc return ref @safe

Get first CompletionEntry from cq ring

front
.
(field) int during.io_uring.CompletionEntry.res

result code for this event

res
;
(local variable) during.Uring io
io
.
void during.Uring.popFront() pure nothrow @nogc @safe

Move to next CompletionEntry

popFront
();
if (
(local variable) const(int) closeRes
closeRes
< 0)
{
int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
(
(local variable) const(int) fd
fd
); // ring CLOSE failed; fall back to a synchronous close
return
int io_uring_openat_statx_close.failErr(string op, int res)
failErr
("CLOSE",
(local variable) const(int) closeRes
closeRes
);
}
void std.stdio.writefln!(char, ulong, const(int))(in char[] fmt, ulong __param_1, const(int) __param_2) @safe

Equivalent to writef(fmt, args, '\n').

writefln
("ok: async OPENAT→STATX(size=%d)→READ(%d bytes)→CLOSE chained through io_uring",
(local variable) io_uring_openat_statx_close.Statx stx
stx
.
(field) ulong io_uring_openat_statx_close.Statx.stx_size
stx_size
,
(local variable) const(int) readRes
readRes
);
return 0; } // --- small helpers ---------------------------------------------------------- // A `const(char)*` to a single NUL byte: an empty C path for STATX-on-fd. const(char)*
const(char)* io_uring_openat_statx_close.emptyCString() nothrow @nogc @trusted
emptyCString
() @trusted nothrow @nogc
{ static immutable char[1]
(immutable global) immutable(char[1]) io_uring_openat_statx_close.emptyCString.empty
empty
= ['\0'];
return &
(immutable global) immutable(char[1]) io_uring_openat_statx_close.emptyCString.empty
empty
[0];
} // libc syscalls return -1 and set errno; this wrapper environment doesn't read // errno portably, so for the setup path we just report the raw -1. int
int io_uring_openat_statx_close.errnoOf(int ret) pure nothrow @nogc @safe
errnoOf
(int
(parameter) int ret
ret
) @safe pure nothrow @nogc => -
(parameter) int ret
ret
;
// io_uring surfaces "this op doesn't exist on this kernel" as -EINVAL/-EOPNOTSUPP/-ENOSYS. bool
bool io_uring_openat_statx_close.isUnsupported(int res) pure nothrow @nogc @safe
isUnsupported
(int
(parameter) int res
res
) @safe pure nothrow @nogc
{ enum int
(constant) int io_uring_openat_statx_close.isUnsupported.EINVAL = 22
EINVAL
= 22,
(constant) int io_uring_openat_statx_close.isUnsupported.ENOSYS = 38
ENOSYS
= 38,
(constant) int io_uring_openat_statx_close.isUnsupported.EOPNOTSUPP = 95
EOPNOTSUPP
= 95;
return
(parameter) int res
res
== -
(constant) int io_uring_openat_statx_close.isUnsupported.EINVAL = 22
EINVAL
||
(parameter) int res
res
== -
(constant) int io_uring_openat_statx_close.isUnsupported.EOPNOTSUPP = 95
EOPNOTSUPP
||
(parameter) int res
res
== -
(constant) int io_uring_openat_statx_close.isUnsupported.ENOSYS = 38
ENOSYS
;
} int
int io_uring_openat_statx_close.fail(string what)
fail
(
(alias) object.string = string
string
(parameter) string what
what
)
{ stderr.
std.stdio.File std.stdio.makeGlobal!"core.stdc.stdio.stderr"() nothrow @nogc @property ref @system
writefln
("%s failed",
(parameter) string what
what
);
return 1; } int
int io_uring_openat_statx_close.failErr(string op, int res)
failErr
(
(alias) object.string = string
string
(parameter) string op
op
, int
(parameter) int res
res
)
{ stderr.
std.stdio.File std.stdio.makeGlobal!"core.stdc.stdio.stderr"() nothrow @nogc @property ref @system
writefln
("%s completed with error: errno %d",
(parameter) string op
op
, -
(parameter) int res
res
);
return 1; } int
int io_uring_openat_statx_close.failClose(int fd, string what)
failClose
(int
(parameter) int fd
fd
,
(alias) object.string = string
string
(parameter) string what
what
)
{
int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
(
(parameter) int fd
fd
);
return
int io_uring_openat_statx_close.fail(string what)
fail
(
(parameter) string what
what
);
} // `octal!"600"` — file mode literal computed at compile time. template
(template) io_uring_openat_statx_close.octal(string digits)
octal
(string digits)
{ enum uint
(constant) uint io_uring_openat_statx_close.octal!"600" = 384u
octal
=
uint io_uring_openat_statx_close.parseOctal(string s) pure nothrow @nogc @safe
parseOctal
(
(constant) string io_uring_openat_statx_close.digits = "600"
digits
);
} uint
uint io_uring_openat_statx_close.parseOctal(string s) pure nothrow @nogc @safe
parseOctal
(
(alias) object.string = string
string
(parameter) string s
s
) @safe pure nothrow @nogc
{ uint
(local variable) uint v
v
= 0;
foreach (
(parameter) immutable(char) c
c
;
(parameter) string s
s
)
(local variable) uint v
v
=
(local variable) uint v
v
* 8 + (
(local variable) immutable(char) c
c
- '0');
return
(local variable) uint v
v
;
}