Inhaltsverzeichnis

std.io_uring — Asynchrones I/O (io_uring)

import std.io_uring;

io_uring ist der moderne Linux-Mechanismus für asynchrones I/O (Kernel 5.1+). SQEs (Submission Queue Entries) werden in einen Ring-Puffer geschrieben, den Kernel dann unabhängig abarbeitet. Abschlüsse erscheinen als CQEs (Completion Queue Entries) im CQ-Ring. Syscall-Overhead wird durch den gemeinsamen mmap-Speicher minimiert.

std.net.epoll · std.fs · Rohspeicher


Konstanten

Opcode-Konstanten (SQE-Typen)

Konstante Wert Beschreibung
IORING_OP_NOP 0 No-Op (Test)
IORING_OP_READV 1 Scatter-Read (iovec)
IORING_OP_WRITEV 2 Gather-Write (iovec)
IORING_OP_TIMEOUT 11 Timeout
IORING_OP_ACCEPT 13 accept4
IORING_OP_CONNECT 16 connect
IORING_OP_READ 22 Einfacher Read
IORING_OP_WRITE 23 Einfacher Write
IORING_OP_SEND 26 send
IORING_OP_RECV 27 recv

SQE-Feld-Offsets

Konstante Offset Typ Bedeutung
SQE_OPCODE 0 uint8 Opcode (IORING_OP_*)
SQE_FLAGS 1 uint8 SQE-Flags
SQE_FD 4 int32 Dateideskriptor
SQE_OFF 8 uint64 Datei-Offset
SQE_ADDR 16 uint64 Puffer-Zeiger
SQE_LEN 24 uint32 Pufferlänge
SQE_USER_DATA 32 uint64 Frei wählbare Kennung

CQE-Feld-Offsets

Konstante Offset Typ Bedeutung
CQE_USER_DATA 0 uint64 Wie in der SQE gesetzt
CQE_RES 8 int32 Ergebnis (negativ = Fehler-errno)

Funktionen

Ring-Verwaltung

Funktion Signatur Beschreibung
IoUringCreate (entries: int64): int64 Initialisiert Ring mit mind. entries Slots; gibt Ring-Handle oder 0 zurück
IoUringFree (ring: int64): int64 Gibt alle Ring-Ressourcen frei (munmap + close)
IoUringFd (ring: int64): int64 Liefert den io_uring-Dateideskriptor
IoUringEnter (fd: int64, toSubmit: int64, minComplete: int64, flags: int64): int64 Direkter sys_io_uring_enter-Aufruf

SQE-Verwaltung

Funktion Signatur Beschreibung
IoUringGetSQE (ring: int64): int64 Nächste freie SQE (auf Null gesetzt); 0 wenn Ring voll
IoUringSubmit (ring: int64): int64 Veröffentlicht alle vorbereiteten SQEs
IoUringSubmitAndWait (ring: int64, minComplete: int64): int64 Submit + blockiert bis minComplete CQEs fertig

CQE-Verwaltung

Funktion Signatur Beschreibung
IoUringPeekCQE (ring: int64): int64 Nächste fertige CQE oder 0 wenn keine vorhanden
IoUringWaitCQE (ring: int64): int64 Blockiert bis eine CQE verfügbar ist
IoUringCQESeen (ring: int64, cqe: int64): int64 Markiert CQE als verarbeitet (Head +1)
IoUringCQEResult (cqe: int64): int64 Liest Ergebnis aus CQE (negativ = Fehler-errno)
IoUringCQEUserData (cqe: int64): int64 Liest user_data-Feld der CQE

SQE-Setup-Helfer

Funktion Beschreibung
IoUringSQESetNop(sqe, userData) No-Op konfigurieren (für Tests)
IoUringSQESetRead(sqe, fd, buf, len, offset, userData) Asynchronen Read konfigurieren
IoUringSQESetWrite(sqe, fd, buf, len, offset, userData) Asynchronen Write konfigurieren

Verwendung

Grundprinzip: NOP-Test

import std.io_uring;

fn main(): int64 {
    var ring: int64 := IoUringCreate(8);
    if (ring = 0) { return -1; }

    var sqe: int64 := IoUringGetSQE(ring);
    if (sqe = 0) { IoUringFree(ring); return -1; }
    IoUringSQESetNop(sqe, 42);

    IoUringSubmit(ring);

    var cqe: int64 := IoUringWaitCQE(ring);
    var res: int64 := IoUringCQEResult(cqe);
    var ud:  int64 := IoUringCQEUserData(cqe);
    IoUringCQESeen(ring, cqe);

    IoUringFree(ring);
    return 0;
}

Asynchroner File-Read

import std.io_uring;
import std.alloc;
import std.fs;

fn AsyncRead(path: pchar, outBuf: int64, bufLen: int64): int64 {
    var fd: int64 := OpenFile(path, 0);
    if (fd < 0) { return fd; }

    var ring: int64 := IoUringCreate(4);
    if (ring = 0) { CloseFile(fd); return -12; }

    var sqe: int64 := IoUringGetSQE(ring);
    IoUringSQESetRead(sqe, fd, outBuf, bufLen, 0, 1);
    IoUringSubmit(ring);

    var cqe: int64 := IoUringWaitCQE(ring);
    var res: int64 := IoUringCQEResult(cqe);
    IoUringCQESeen(ring, cqe);

    IoUringFree(ring);
    CloseFile(fd);
    return res;  // Anzahl gelesener Bytes oder negatives errno
}

Mehrere Operationen parallel

import std.io_uring;
import std.alloc;

fn MultiWrite(fd: int64, buf1: int64, len1: int64,
                          buf2: int64, len2: int64): int64 {
    var ring: int64 := IoUringCreate(8);
    if (ring = 0) { return -12; }

    // Zwei Writes in den Ring stellen
    var sqe1: int64 := IoUringGetSQE(ring);
    IoUringSQESetWrite(sqe1, fd, buf1, len1, 0, 100);

    var sqe2: int64 := IoUringGetSQE(ring);
    IoUringSQESetWrite(sqe2, fd, buf2, len2, len1, 200);

    // Beide abschicken, auf beide warten
    IoUringSubmitAndWait(ring, 2);

    var result: int64 := 0;
    var i: int64 := 0;
    while (i < 2) {
        var cqe: int64 := IoUringPeekCQE(ring);
        if (cqe != 0) {
            var res: int64 := IoUringCQEResult(cqe);
            if (res < 0) { result := res; }
            IoUringCQESeen(ring, cqe);
        }
        i := i + 1;
    }

    IoUringFree(ring);
    return result;
}


Hinweise


Letzte Aktualisierung: 2026-06-05