Completion

Introduction

These functions deal with completion of I/O requests in io_uring. The snippet below is from the example cat with liburing. While there are other possible ways, it shows a general way in which you can use completion related functions. Once a request or multiple requests have been submitted, you can wait for a completion and process it as shown below.

int get_completion_and_print(struct io_uring *ring) {
    struct io_uring_cqe *cqe;
    int ret = io_uring_wait_cqe(ring, &cqe);

    if (ret < 0) {
        perror("io_uring_wait_cqe");
        return 1;
    }

    if (cqe->res < 0) {
        /* The system call invoked asynchonously failed */
        return 1;
    }

    /* Retrieve user data from CQE */
    struct file_info *fi = io_uring_cqe_get_data(cqe);
    /* process this request here */

    /* Mark this completion as seen */
    io_uring_cqe_seen(ring, cqe);
    return 0;
}
  • You can wait for a completion by calling io_uring_wait_cqe(). This function blocks until at least one completion is available.

  • It fills up details of the completion in the io_uring_cqe structure.

  • This structure’s res member contains the return value of the system call that was executed as part of the request. For example, if io_uring_prep_read() was called to process a read(2) like request, res will contain the number of characters read or if it is less than zero, denotes that read(2) faced an error.

  • In io_uring, you can set a user data field in the submission side, which with kernel will then make available unchanged on the completion side. You can use this to uniquely identify requests. You can get the user data pointer from the CQE by calling io_uring_cqe_get_data().

  • Once you process the information you got from the completion, you need to mark the CQE as “seen”. You can do this with the io_uring_cqe_seen() function.

Reference

int io_uring_wait_cqe(struct io_uring *ring, struct io_uring_cqe **cqe_ptr)

Returns an I/O completion, waiting for it if necessary.

Parameters

Return value

Returns 0 with cqe_ptr filled in on success, -errno on failure.


int io_uring_wait_cqe_nr(struct io_uring *ring, struct io_uring_cqe **cqe_ptr, unsigned wait_nr)

Return an IO completion, waiting for wait_nr completions if one isn’t readily available.

Parameters

  • ring: io_uring structure as set up by io_uring_queue_init().

  • cqe_ptr: pointer to a pointer to a io_uring_cqe structure.

  • wait_nr: number of completions to wait for.

Return value

Returns 0 with cqe_ptr filled in on success, -errno on failure.


int io_uring_wait_cqes(struct io_uring *ring, struct io_uring_cqe **cqe_ptr, unsigned wait_nr, struct __kernel_timespec *ts, sigset_t *sigmask)

Like io_uring_wait_cqe(), except it accepts a timeout value as well. Note that an SQE is used internally to handle the timeout. Applications using this function must never set sqe->user_data to LIBURING_UDATA_TIMEOUT.

If ts is specified, the application need not call io_uring_submit() before calling this function, as it will be done internally. From this it also follows that this function isn’t safe to use for applications that split SQ and CQ handling between two threads and expect that to work without synchronization, as this function manipulates both the SQ and CQ side.

Parameters

  • ring: io_uring structure as set up by io_uring_queue_init().

  • cqe_ptr: pointer to a pointer to a io_uring_cqe structure.

  • wait_nr: number of completions to wait for.

  • ts: pointer to a __kernel_timespec structure.

  • sigmask: a pointer to sigset_t, the set of signals to block. The prevailing signal mask is restored before returning.

Return value

Returns 0 with cqe_ptr filled in on success, -errno on failure.


int io_uring_wait_cqe_timeout(struct io_uring *ring, struct io_uring_cqe **cqe_ptr, struct __kernel_timespec *ts)

Same as the io_uring_wait_cqes() except it does not take a sigmask argument and always sets wait_nr to 1.


int io_uring_peek_cqe(struct io_uring *ring, struct io_uring_cqe **cqe_ptr)

Returns an I/O completion, if one is readily available. Doesn’t wait.

Parameters

Return value

Returns 0 with cqe_ptr filled in on success, -errno on failure.


unsigned io_uring_peek_batch_cqe(struct io_uring *ring, struct io_uring_cqe **cqes, unsigned count)

Fills in an array of I/O completions up to count, if they are available, returning the count of completions filled. Does not wait for completions. They have to be already available for them to be returned by this function.

Parameters

  • ring: io_uring structure as set up by io_uring_queue_init().

  • cqe_ptr: pointer to a pointer to a io_uring_cqe structure.

  • count: count of completions to fetch.

Return value

Returns the count of I/O completions filled.


void *io_uring_cqe_get_data(const struct io_uring_cqe *cqe)

Returns pointer to user data set with :c:func`io_uring_sqe_set_data`.

Parameters

  • cqe: pointer to the CQE from which to fetch the user data pointer.

Return value

Returns pointer to user data.


void io_uring_cqe_seen(struct io_uring *ring, struct io_uring_cqe *cqe)

Must be called after io_uring_peek_cqe() or io_uring_wait_cqe() and after the cqe has been processed by the application.

Parameters


unsigned io_uring_cq_ready(struct io_uring *ring)

TODO: add documentation