本文へ移動
cccskills
無料GitHub で公開

io-uring

Use when building Linux servers with liburing, batching SQEs, multi-shot operations, provided buffer rings, registered files and buffers, or zero-copy send. Not for packet I/O: use af-xdp.

インストール方法を見る

含まれるファイル(2)

  • SKILL.md7.5 KB
  • agents/openai.yaml218 B

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

io_uring

Contract

FieldBound contract
TriggerBuilding or tuning Linux async I/O with io_uring: the SQE/CQE model, liburing usage, multi-shot accept or recv, provided buffer rings, fixed files and buffers, zero-copy send, tokio-uring, or the io_uring versus epoll decision.
AuthorityRead-only. Writes nothing. Chat output only. No remote mutation.
Side effectReturns setup code, ring lifecycle rules, and a comparison verdict. No source files are modified.
DoneThe liburing example, the multi-shot and buffer-ring patterns, the zero-copy rule, and the epoll comparison verdict are delivered.

Inputs

  1. Workload shape (required): network or disk, operation mix, and connection count.
  2. Kernel (required): the running version, because io_uring features vary by version; base support starts at 5.1.
  3. Language (optional): C with liburing, or Rust with tokio-uring.

Procedure

  1. State the queue model. Each SQE describes one operation. Each CQE reports a result and the user_data cookie that identifies the operation. io_uring_submit() pushes SQEs to the kernel; io_uring_wait_cqe() blocks for a completion. Done when: the SQE-to-CQE flow with the cookie rule is stated in the delivered guidance.

  2. Show the minimal liburing loop as the reference shape.

    #include <liburing.h>
    
    struct io_uring ring;
    io_uring_queue_init(32, &ring, 0);
    
    struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
    io_uring_prep_read(sqe, fd, buf, sizeof(buf), 0);
    io_uring_sqe_set_data(sqe, (void *)1);
    io_uring_submit(&ring);
    
    struct io_uring_cqe *cqe;
    io_uring_wait_cqe(&ring, &cqe);
    if (cqe->res >= 0)
        handle(cqe->res);
    io_uring_cqe_seen(&ring, cqe);
    io_uring_queue_exit(&ring);
    

    Build with -luring. Done when: the example compiles against liburing and each CQE is consumed with cqe_seen.

  3. Map the request to its prep function: io_uring_prep_read, prep_write, prep_recv, prep_send, prep_accept, prep_connect, prep_poll_add, prep_timeout. Batch many SQEs between submits; one submit amortizes the syscall cost over the batch. Done when: every operation in the workload has a prep function and a batching point.

  4. Use multi-shot operations for connection-heavy paths. One io_uring_prep_multishot_accept SQE keeps producing completions until it reports completion of its own life.

    io_uring_prep_multishot_accept(sqe, listen_fd, NULL, NULL, 0);
    io_uring_sqe_set_data(sqe, (void *)ACCEPT_COOKIE);
    
    io_uring_wait_cqe(&ring, &cqe);
    if (cqe->user_data == ACCEPT_COOKIE && cqe->res >= 0)
        handle_client(cqe->res);
    int more = cqe->flags & IORING_CQE_F_MORE;
    io_uring_cqe_seen(&ring, cqe);
    if (!more)
        rearm_accept(); /* the multishot SQE ended; submit a new one */
    

    Done when: the loop re-arms exactly when IORING_CQE_F_MORE is clear.

  5. Use provided buffer rings for recv paths. The kernel picks a buffer from the ring, which removes the per-recv allocation.

    #define BUF_SIZE  4096
    #define BUF_COUNT 64
    
    int ret;
    struct io_uring_buf_ring *buf_ring =
        io_uring_setup_buf_ring(&ring, BUF_COUNT, BUF_GROUP, 0, &ret);
    for (int i = 0; i < BUF_COUNT; i++)
        /* mask is ring size - 1; offset walks the slots */
        io_uring_buf_ring_add(buf_ring, bufs[i], BUF_SIZE, i, BUF_COUNT - 1, i);
    io_uring_buf_ring_advance(buf_ring, BUF_COUNT);
    
    sqe = io_uring_get_sqe(&ring);
    io_uring_prep_recv_multishot(sqe, sock_fd, NULL, 0, 0);
    sqe->buf_group = BUF_GROUP;
    

    Return each consumed buffer with io_uring_buf_ring_add before the next advance. Done when: every consumed buffer is re-added, and the recv carries the buffer group.

  6. Register files and buffers on hot paths. Registered files avoid the per-operation fd table lookup; registered buffers are pinned and suited to *_fixed operations.

    io_uring_register_files(&ring, fds, 64);
    io_uring_prep_read(sqe, 0, buf, size, offset); /* index into the table, not the fd */
    struct iovec iov = { .iov_base = buf, .iov_len = size };
    io_uring_register_buffers(&ring, &iov, 1);
    io_uring_prep_read_fixed(sqe, fd, buf, size, offset, 0);
    

    Done when: hot-path operations use fixed variants and the registered tables are updated on fd churn.

  7. Use zero-copy send where available. io_uring_prep_send_zc needs kernel 6.0 or later and falls back to a normal send when the protocol or device does not support it. A zero-copy send posts a second notification CQE; treat IORING_CQE_F_MORE on the first CQE as the signal to wait for it. Done when: the send path handles the notification CQE and the fallback.

  8. For Rust, show the tokio-uring shape: the runtime owns the ring and returns buffer ownership with the result.

    use tokio_uring::fs::File;
    
    #[tokio_uring::main]
    async fn main() -> std::io::Result<()> {
        let file = File::open("test.txt").await?;
        let buf = vec![0u8; 4096];
        let (res, buf) = file.read_at(buf, 0).await;
        println!("read {} bytes", res?);
        Ok(())
    }
    

    Done when: the Rust example compiles with the tokio-uring crate and buffer ownership flow is stated.

  9. Deliver the epoll comparison as a verdict, not a table of absolutes.

    Aspectepollio_uring
    SyscallsOne per operation plus epoll_waitBatched SQEs, one submit
    BuffersApplication allocates per opProvided buffer rings
    Zero-copy sendManualSEND_ZC built in
    PortabilityEverywhere5.1+, feature-dependent

    Choose io_uring when syscall overhead is measured, not assumed, and the kernel has the needed operations. Stay on epoll for simple services and portability. Probe support at runtime with io_uring_get_probe(). Done when: the verdict cites a measured syscall or batching cost.

  10. State the security posture. Some distributions restrict io_uring by default because it has been an attack surface.

sysctl kernel.io_uring_disabled
# 0: all processes may create instances
# 1: CAP_SYS_ADMIN or members of kernel.io_uring_group only
# 2: creation off for everyone
sysctl kernel.io_uring_group   # the gid allowed at level 1

Existing instances keep working after a policy change. Keep the kernel patched and sandbox untrusted code. Done when: the deployment documents its io_uring policy and kernel version.

Failure and recovery

SymptomCauseRecovery
-EINVAL on prepOperation unsupported on this kernelCheck io_uring_get_probe(); gate the code path on it.
Hang on wait_cqeSQEs never submittedCall io_uring_submit after preparing.
Buffer never returnedConsumed buffer not re-addedRe-add with buf_ring_add after consuming.
SEND_ZC result unclearNotification CQE pendingWait for the second CQE; IORING_CQE_F_MORE marks the pair.
Slower than epollTiny batchesBatch more SQEs per submit; consider SQPOLL.
-EPERM on setupio_uring restricted by sysctlAlign with the kernel.io_uring_disabled policy.

Output

The queue-model statement; the minimal liburing example; the prep-function mapping and batching plan; the multi-shot and buffer-ring code; the registration rules; the zero-copy send rule; the tokio-uring example; the epoll verdict with its measured basis; the security posture.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Use when explaining System V AMD64, ARM AAPCS, RISC-V psABI, stack frames, variadic calls, or FFI register rules. Not for the Rust FFI binding layer: use rust-ffi.

日本語の概要は準備中です。原文の説明を表示しています。

OutlineDriven/odin-claude-plugin372026年9月29日 更新

Use when configuring ADC sampling time, DMA-driven ADC, calibration, or DAC channel setup on bare-metal MCUs. Not for the DMA stream itself: use dma-baremetal.

日本語の概要は準備中です。原文の説明を表示しています。

OutlineDriven/odin-claude-plugin372026年9月29日 更新

af-xdp

無料

Use when creating AF_XDP sockets, configuring UMEM and XSK rings, writing an XDP redirect program, or choosing copy versus zero-copy mode. Not for full kernel bypass: use dpdk.

日本語の概要は準備中です。原文の説明を表示しています。

OutlineDriven/odin-claude-plugin372026年9月29日 更新

Use when a completed session needs an agent-environment retrospective. Not for an engineering retrospective from telemetry: use engineering-retrospective.

日本語の概要は準備中です。原文の説明を表示しています。

OutlineDriven/odin-claude-plugin372026年9月29日 更新

Use when a redacted, trimmed agent transcript must be appended to a GitHub PR or issue body, with human approval and preview. Not for automated or model-initiated insertion.

日本語の概要は準備中です。原文の説明を表示しています。

OutlineDriven/odin-claude-plugin372026年9月29日 更新

agents-md

無料

Use when a repo needs agent setup, AGENTS.md added or made lean, CLAUDE.md audited, or agent instructions scored or pruned. Not for remote, credential, publish, deploy, or irreversible changes.

日本語の概要は準備中です。原文の説明を表示しています。

OutlineDriven/odin-claude-plugin372026年9月29日 更新

OutlineDriven のスキルをすべて見る

このスキルの問題を報告する