direct-descriptors.dhover×187all
#!/usr/bin/env dub
/+ dub.sdl:
    name "io_uring_direct_descriptors"
    dependency "during" version="~>0.5.0"
    platforms "linux"
    targetPath "build"
+/
/**
 * `io_uring` — direct (registered) descriptors + `FIXED_FD_INSTALL`
 * (`IORING_OP_OPENAT` direct-open, Linux 5.15; `FIXED_FD_INSTALL`, Linux 6.8).
 *
 * Direct descriptors live in the ring's registered-files table instead of the
 * process fd table: a direct `openat` deposits the kernel file object straight
 * into a table slot and never allocates a userspace fd. Ops then address that
 * slot *by index* with the `IOSQE_FIXED_FILE` flag, which skips the per-op fd
 * lookup/refcount and removes the open-file from `/proc/<pid>/fd`. This example
 * walks the full life cycle:
 *
 *   1. `registerFiles([-1])` reserves one sparse (empty) slot in the table.
 *   2. `OPENAT_DIRECT` opens a temp file straight into slot 0 (no process fd).
 *   3. A `READ` addresses slot 0 via index 0 + `FIXED_FILE` — proving the file
 *      is usable purely by table index.
 *   4. `FIXED_FD_INSTALL` (6.8) materializes slot 0 back into a *real* process
 *      fd, returned in the CQE `res`; a plain libc `read()` through it confirms.
 *
 * Companion to the io_uring chronology:
 * see docs/research/async-io/io-uring/timeline.md
 *   § "5.15 — More filesystem ops, worker caps (October 2021)" (direct descriptors)
 *   and § "6.8 — Fixed-fd install, pbuf status (March 2024)" (FIXED_FD_INSTALL).
 *
 * Run with: `dub run --single direct-descriptors.d`
 *
 * Portability: if `io_uring` is unavailable, registered files / direct open are
 * unsupported, or `FIXED_FD_INSTALL` is missing (pre-6.8), the program prints a
 * `SKIP:` line and exits 0 so it stays green in CI regardless of host kernel.
 */
module 
(module) io_uring_direct_descriptors

io_uring — direct (registered) descriptors + FIXED_FD_INSTALL (IORING_OP_OPENAT direct-open, Linux 5.15; FIXED_FD_INSTALL, Linux 6.8).

Direct descriptors live in the ring's registered-files table instead of the process fd table: a direct openat deposits the kernel file object straight into a table slot and never allocates a userspace fd. Ops then address that slot by index with the IOSQE_FIXED_FILE flag, which skips the per-op fd lookup/refcount and removes the open-file from /proc/<pid>/fd. This example walks the full life cycle:

  1. registerFiles([-1]) reserves one sparse (empty) slot in the table.

  2. OPENAT_DIRECT opens a temp file straight into slot 0 (no process fd).

  3. A READ addresses slot 0 via index 0 + FIXED_FILE — proving the file is usable purely by table index.

  4. FIXED_FD_INSTALL (6.8) materializes slot 0 back into a real process fd, returned in the CQE res; a plain libc read() through it confirms.

Companion to the io_uring chronology: see docs/research/async-io/io-uring/timeline.md § "5.15 — More filesystem ops, worker caps (October 2021)" (direct descriptors) and § "6.8 — Fixed-fd install, pbuf status (March 2024)" (FIXED_FD_INSTALL).

Run with: dub run --single direct-descriptors.d

Portability

if io_uring is unavailable, registered files / direct open are unsupported, or FIXED_FD_INSTALL is missing (pre-6.8), the program prints a SKIP: line and exits 0 so it stays green in CI regardless of host kernel.

io_uring_direct_descriptors
;
import
(module) during

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

during
;
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
:
(alias template) io_uring_direct_descriptors.writefln = std.stdio.writefln(alias fmt, A...)(A args) if (isSomeString!(typeof(fmt)))

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

writefln
, stderr;
import
(package) core
core
.
(package) core.sys
sys
.
(package) core.sys.linux
linux
.
(module) core.sys.linux.errno

D header file for GNU/Linux

glibc stdlib/errno.h

errno
:
(alias constant) io_uring_direct_descriptors.EINVAL = int core.stdc.errno.EINVAL = 22
EINVAL
,
(alias constant) io_uring_direct_descriptors.EOPNOTSUPP = int core.stdc.errno.EOPNOTSUPP = 95
EOPNOTSUPP
,
(alias constant) io_uring_direct_descriptors.ENOSYS = int core.stdc.errno.ENOSYS = 38
ENOSYS
,
(alias constant) io_uring_direct_descriptors.EPERM = int core.stdc.errno.EPERM = 1
EPERM
;
import
(package) core
core
.
(package) core.sys
sys
.
(package) core.sys.linux
linux
.
(module) core.sys.linux.fcntl
fcntl
:
(alias constant) io_uring_direct_descriptors.AT_FDCWD = int core.sys.posix.fcntl.AT_FDCWD = -100
AT_FDCWD
,
(alias constant) io_uring_direct_descriptors.O_CREAT = int core.sys.posix.fcntl.O_CREAT = 64
O_CREAT
,
(alias constant) io_uring_direct_descriptors.O_RDONLY = int core.sys.posix.fcntl.O_RDONLY = 0
O_RDONLY
,
(alias constant) io_uring_direct_descriptors.O_WRONLY = int core.sys.posix.fcntl.O_WRONLY = 1
O_WRONLY
;
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_direct_descriptors.close = int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
,
(alias) io_uring_direct_descriptors.read = long core.sys.posix.unistd.read(int, void*, ulong) nothrow @nogc
read
,
(alias) io_uring_direct_descriptors.unlink = int core.sys.posix.unistd.unlink(scope const(char*)) nothrow @nogc
unlink
,
(alias) io_uring_direct_descriptors.write = long core.sys.posix.unistd.write(int, scope const(void*), ulong) nothrow @nogc
write
;
// The eight payload bytes we write to the temp file and expect to read back — // twice: once through the registered slot, once through the installed real fd. private static immutable ubyte[8]
(immutable global) immutable(ubyte[8]) io_uring_direct_descriptors.payload
payload
= [10, 20, 30, 40, 50, 60, 70, 80];
// `true` for the transient "feature not available on this kernel" errnos, so a // missing capability becomes a clean SKIP rather than a hard failure. private bool
bool io_uring_direct_descriptors.unsupported(int res) pure nothrow @nogc @safe
unsupported
(int
(parameter) int res
res
) @safe pure nothrow @nogc
{ return
(parameter) int res
res
== -
(constant) int core.stdc.errno.EINVAL = 22
EINVAL
||
(parameter) int res
res
== -
(constant) int core.stdc.errno.EOPNOTSUPP = 95
EOPNOTSUPP
||
(parameter) int res
res
== -
(constant) int core.stdc.errno.ENOSYS = 38
ENOSYS
||
(parameter) int res
res
== -
(constant) int core.stdc.errno.EPERM = 1
EPERM
;
} int
int D main()
main
()
{
(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; } // Reserve a single *sparse* slot: -1 means "empty", ready to receive a // direct-opened file. The table must exist before OPENAT_DIRECT can target it. int[1]
(local variable) int[1] sparse
sparse
= -1;
const
(local variable) const(int) regRet
regRet
=
(local variable) during.Uring io
io
.
int during.Uring.registerFiles(const(int)[] fds) nothrow @nogc

Register files for I/O.

To make use of the registered files, the IOSQE_FIXED_FILE flag must be set in the flags member of the SubmissionEntry, and the fd member is set to the index of the file in the file descriptor array.

Files are automatically unregistered when the io_uring instance is torn down. An application need only unregister if it wishes to register a new set of fds.

Use -1 as a file descriptor to mark it as reserved in the array.*

@paramfds array of file descriptors to be registered@returnsOn success, returns 0. On error, -errno is returned.
registerFiles
(
(local variable) int[1] sparse
sparse
[]);
if (
(local variable) const(int) regRet
regRet
!= 0)
{ if (
bool io_uring_direct_descriptors.unsupported(int res) pure nothrow @nogc @safe
unsupported
(
(local variable) const(int) regRet
regRet
))
{
void std.stdio.writefln!(char, const(int))(in char[] fmt, const(int) __param_1) @safe

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

writefln
("SKIP: registerFiles unsupported (errno %d)", -
(local variable) const(int) regRet
regRet
);
return 0; } stderr.
std.stdio.File std.stdio.makeGlobal!"core.stdc.stdio.stderr"() nothrow @nogc @property ref @system
writefln
("registerFiles failed: errno %d", -
(local variable) const(int) regRet
regRet
);
return 1; } scope (exit)
(local variable) during.Uring io
io
.
int during.Uring.unregisterFiles() nothrow @nogc @trusted

All previously registered files associated with the io_uring instance will be unregistered.

Files are automatically unregistered when the io_uring instance is torn down. An application need only unregister if it wishes to register a new set of fds.

@returnsOn success, returns 0. On error, -errno is returned.
unregisterFiles
();
// Create a temp file with the known payload using ordinary libc I/O, then // close it — io_uring will reopen it directly into the table. enum
(alias) object.string = string
string
(constant) string io_uring_direct_descriptors.main.path = "/tmp/io_uring_direct_descriptors_demo\0"
path
= "/tmp/io_uring_direct_descriptors_demo\0";
{ const
(local variable) const(int) fd
fd
=
int io_uring_direct_descriptors.openFile(const(char)* path) nothrow @nogc @trusted
openFile
(
(constant) string io_uring_direct_descriptors.main.path = "/tmp/io_uring_direct_descriptors_demo\0"
path
.
(constant) immutable(char)* "/tmp/io_uring_direct_descriptors_demo\0".ptr = "/tmp/io_uring_direct_descriptors_demo\0"
ptr
);
if (
(local variable) const(int) fd
fd
< 0)
{ stderr.
std.stdio.File std.stdio.makeGlobal!"core.stdc.stdio.stderr"() nothrow @nogc @property ref @system
writefln
("could not create temp file");
return 1; } const
(local variable) const(long) w
w
=
long core.sys.posix.unistd.write(int, scope const(void*), ulong) nothrow @nogc
write
(
(local variable) const(int) fd
fd
, &
(immutable global) immutable(ubyte[8]) io_uring_direct_descriptors.payload
payload
[0],
(immutable global) immutable(ubyte[8]) io_uring_direct_descriptors.payload
payload
.
(constant) ulong immutable(ubyte[8]).length = 8LU
length
);
int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
(
(local variable) const(int) fd
fd
);
if (
(local variable) const(long) w
w
!=
(immutable global) immutable(ubyte[8]) io_uring_direct_descriptors.payload
payload
.
(constant) ulong immutable(ubyte[8]).length = 8LU
length
)
{ stderr.
std.stdio.File std.stdio.makeGlobal!"core.stdc.stdio.stderr"() nothrow @nogc @property ref @system
writefln
("short write to temp file (%d)",
(local variable) const(long) w
w
);
return 1; } } scope (exit)
int core.sys.posix.unistd.unlink(scope const(char*)) nothrow @nogc
unlink
(
(constant) string io_uring_direct_descriptors.main.path = "/tmp/io_uring_direct_descriptors_demo\0"
path
.
(constant) immutable(char)* "/tmp/io_uring_direct_descriptors_demo\0".ptr = "/tmp/io_uring_direct_descriptors_demo\0"
ptr
);
// --- Step 1: OPENAT_DIRECT — open straight into registered slot 0. --------- // No process fd is allocated; the file object lands in the files table only.
(local variable) during.Uring io
io
.putWith!((ref SubmissionEntry e, const(char)* p) {
e.prepOpenatDirect(AT_FDCWD, p, O_RDONLY, 0, /*fileIndex=*/ 0); e.user_data = 1; })(
during.Uring during.Uring.putWith!(function (ref during.io_uring.SubmissionEntry e, const(char)* p) nothrow @nogc @system { prepOpenatDirect(e, -100, p, 0, 0u, 0u); e.user_data = 1LU; } , immutable(char)*)(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.
path
.
during.Uring during.Uring.putWith!(function (ref during.io_uring.SubmissionEntry e, const(char)* p) nothrow @nogc @system { prepOpenatDirect(e, -100, p, 0, 0u, 0u); e.user_data = 1LU; } , immutable(char)*)(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.
ptr
);
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) != 1) { stderr.
std.stdio.File std.stdio.makeGlobal!"core.stdc.stdio.stderr"() nothrow @nogc @property ref @system
writefln
("submit (open) failed"); return 1; }
(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) res
res
=
(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_direct_descriptors.unsupported(int res) pure nothrow @nogc @safe
unsupported
(
(local variable) const(int) res
res
))
{
void std.stdio.writefln!(char, const(int))(in char[] fmt, const(int) __param_1) @safe

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

writefln
("SKIP: OPENAT_DIRECT unsupported (errno %d)", -
(local variable) const(int) res
res
);
return 0; } if (
(local variable) const(int) res
res
!= 0)
{ stderr.
std.stdio.File std.stdio.makeGlobal!"core.stdc.stdio.stderr"() nothrow @nogc @property ref @system
writefln
("OPENAT_DIRECT failed: errno %d", -
(local variable) const(int) res
res
);
return 1; } } // --- Step 2: READ addressing slot 0 by index, with the FIXED_FILE flag. ---- // The "fd" we pass is the *table index* (0); FIXED_FILE tells the kernel to // resolve it through the registered-files table instead of the process table. ubyte[8]
(local variable) ubyte[8] viaIndex
viaIndex
;
(local variable) during.Uring io
io
.putWith!((ref SubmissionEntry e, ubyte[] buf) {
e.prepRead(/*index=*/ 0, buf, /*offset=*/ 0); e.flags |= SubmissionEntryFlags.FIXED_FILE; e.user_data = 2; })(
during.Uring during.Uring.putWith!(function (ref during.io_uring.SubmissionEntry e, ubyte[] buf) nothrow @nogc @safe { prepRead(e, 0, buf, 0L); cast(int)e.flags |= 1; e.user_data = 2LU; } , ubyte[])(ubyte[] __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.
viaIndex
[]);
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) != 1) { stderr.
std.stdio.File std.stdio.makeGlobal!"core.stdc.stdio.stderr"() nothrow @nogc @property ref @system
writefln
("submit (read-by-index) failed"); return 1; }
(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) res
res
=
(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) res
res
< 0)
{ stderr.
std.stdio.File std.stdio.makeGlobal!"core.stdc.stdio.stderr"() nothrow @nogc @property ref @system
writefln
("FIXED_FILE READ failed: errno %d", -
(local variable) const(int) res
res
);
return 1; } if (
(local variable) const(int) res
res
!=
(immutable global) immutable(ubyte[8]) io_uring_direct_descriptors.payload
payload
.
(constant) ulong immutable(ubyte[8]).length = 8LU
length
||
(local variable) ubyte[8] viaIndex
viaIndex
!=
(immutable global) immutable(ubyte[8]) io_uring_direct_descriptors.payload
payload
)
{ stderr.
std.stdio.File std.stdio.makeGlobal!"core.stdc.stdio.stderr"() nothrow @nogc @property ref @system
writefln
("read-by-index payload mismatch (res=%d)",
(local variable) const(int) res
res
);
return 1; } } // --- Step 3: FIXED_FD_INSTALL — promote slot 0 to a real process fd. ------- // This op (6.8) is itself issued against the table index; prepFixedFdInstall // sets FIXED_FILE for us. The new, ordinary fd is returned in the CQE res.
(local variable) during.Uring io
io
.putWith!((ref SubmissionEntry e) {
e.prepFixedFdInstall(/*fixedFd=*/ 0, /*flags=*/ 0); e.user_data = 3; })(); 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) != 1) { stderr.
std.stdio.File std.stdio.makeGlobal!"core.stdc.stdio.stderr"() nothrow @nogc @property ref @system
writefln
("submit (install) failed"); return 1; }
(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);
int
(local variable) int newFd
newFd
;
{ const
(local variable) const(int) res
res
=
(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_direct_descriptors.unsupported(int res) pure nothrow @nogc @safe
unsupported
(
(local variable) const(int) res
res
))
{
void std.stdio.writefln!(char, const(int))(in char[] fmt, const(int) __param_1) @safe

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

writefln
("SKIP: FIXED_FD_INSTALL unsupported (errno %d) — needs Linux 6.8+", -
(local variable) const(int) res
res
);
return 0; } if (
(local variable) const(int) res
res
< 0)
{ stderr.
std.stdio.File std.stdio.makeGlobal!"core.stdc.stdio.stderr"() nothrow @nogc @property ref @system
writefln
("FIXED_FD_INSTALL failed: errno %d", -
(local variable) const(int) res
res
);
return 1; }
(local variable) int newFd
newFd
=
(local variable) const(int) res
res
;
} scope (exit)
int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
(
(local variable) int newFd
newFd
);
// --- Step 4: confirm the installed fd is a normal, readable process fd. ---- ubyte[8]
(local variable) ubyte[8] viaRealFd
viaRealFd
;
const
(local variable) const(long) rd
rd
=
long core.sys.posix.unistd.read(int, void*, ulong) nothrow @nogc
read
(
(local variable) int newFd
newFd
, &
(local variable) ubyte[8] viaRealFd
viaRealFd
[0],
(local variable) ubyte[8] viaRealFd
viaRealFd
.
(constant) ulong ubyte[8].length = 8LU
length
);
if (
(local variable) const(long) rd
rd
!=
(immutable global) immutable(ubyte[8]) io_uring_direct_descriptors.payload
payload
.
(constant) ulong immutable(ubyte[8]).length = 8LU
length
||
(local variable) ubyte[8] viaRealFd
viaRealFd
!=
(immutable global) immutable(ubyte[8]) io_uring_direct_descriptors.payload
payload
)
{ stderr.
std.stdio.File std.stdio.makeGlobal!"core.stdc.stdio.stderr"() nothrow @nogc @property ref @system
writefln
("installed real fd read mismatch (rd=%d)",
(local variable) const(long) rd
rd
);
return 1; }
void std.stdio.writefln!(char, int)(in char[] fmt, int __param_1) @safe

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

writefln
("ok: direct fd opened into table slot 0, read by index, then "
~ "FIXED_FD_INSTALL → real fd %d (both reads returned the same 8 bytes)",
(local variable) int newFd
newFd
);
return 0; } // Thin libc `open(path, O_CREAT|O_WRONLY, 0600)` wrapper — `core.sys.posix`'s // `open` is variadic, which is awkward to call from a `@trusted` context, so we // bind the C symbol directly. private int
int io_uring_direct_descriptors.openFile(const(char)* path) nothrow @nogc @trusted
openFile
(const(char)*
(parameter) const(char)* path
path
) @trusted nothrow @nogc
{ import
(package) std
std
.
(module) std.conv

A one-stop shop for converting values from one type to another.

Category Functions
Generic asOriginalType castFrom parse to toChars bitCast
Strings text wtext dtext writeText writeWText writeDText hexString
Numeric octal roundTo signed unsigned
Exceptions ConvException ConvOverflowException

Source

std/conv.d

@copyrightCopyright The D Language Foundation 2007-.@licenseBoost License 1.0.@authorsWalter Bright, Andrei Alexandrescu, Shin Fujishiro, Adam D. Ruppe, Kenji Hara
conv
:
(alias template) octal = std.conv.octal(string num) if (isOctalLiteral(num))

The octal facility provides a means to declare a number in base 8. Using octal!177 or octal!"177" for 127 represented in octal (same as 0177 in C).

The rules for strings are the usual for literals: If it can fit in an int, it is an int. Otherwise, it is a long. But, if the user specifically asks for a long with the L suffix, always give the long. Give an unsigned iff it is asked for with the $(D U) or u suffix. _Octals created from integers preserve the type of the passed-in integral.

See_Also: $(LREF parse) for parsing octal strings at runtime.

octal
;
return
int io_uring_direct_descriptors.open(const(char)* path, int flags, ...) nothrow @nogc @trusted
c_open
(
(parameter) const(char)* path
path
,
(constant) int core.sys.posix.fcntl.O_CREAT = 64
O_CREAT
|
(constant) int core.sys.posix.fcntl.O_WRONLY = 1
O_WRONLY
,
(template instance) std.conv.octal!600
octal
!600);
} extern (C) private int
int io_uring_direct_descriptors.open(const(char)* path, int flags, ...) nothrow @nogc @trusted
open
(const(char)*
(parameter) const(char)* path
path
, int
(parameter) int flags
flags
, ...) @trusted nothrow @nogc;
private alias
(alias) io_uring_direct_descriptors.c_open = int io_uring_direct_descriptors.open(const(char)* path, int flags, ...) nothrow @nogc @trusted
c_open
=
int io_uring_direct_descriptors.open(const(char)* path, int flags, ...) nothrow @nogc @trusted
open
;