Linux Audio

Check our new training course

Real-Time Linux with PREEMPT_RT training

Feb 18-20, 2025
Register
Loading...
Note: File does not exist in v6.13.7.
  1#include <sys/types.h>
  2#include <sys/stat.h>
  3#include <sys/mman.h>
  4#include <unistd.h>
  5#include <errno.h>
  6#include <string.h>
  7
  8#include "liburing.h"
  9#include "barrier.h"
 10
 11static int __io_uring_get_cqe(struct io_uring *ring,
 12			      struct io_uring_cqe **cqe_ptr, int wait)
 13{
 14	struct io_uring_cq *cq = &ring->cq;
 15	const unsigned mask = *cq->kring_mask;
 16	unsigned head;
 17	int ret;
 18
 19	*cqe_ptr = NULL;
 20	head = *cq->khead;
 21	do {
 22		/*
 23		 * It's necessary to use a read_barrier() before reading
 24		 * the CQ tail, since the kernel updates it locklessly. The
 25		 * kernel has the matching store barrier for the update. The
 26		 * kernel also ensures that previous stores to CQEs are ordered
 27		 * with the tail update.
 28		 */
 29		read_barrier();
 30		if (head != *cq->ktail) {
 31			*cqe_ptr = &cq->cqes[head & mask];
 32			break;
 33		}
 34		if (!wait)
 35			break;
 36		ret = io_uring_enter(ring->ring_fd, 0, 1,
 37					IORING_ENTER_GETEVENTS, NULL);
 38		if (ret < 0)
 39			return -errno;
 40	} while (1);
 41
 42	return 0;
 43}
 44
 45/*
 46 * Return an IO completion, if one is readily available. Returns 0 with
 47 * cqe_ptr filled in on success, -errno on failure.
 48 */
 49int io_uring_peek_cqe(struct io_uring *ring, struct io_uring_cqe **cqe_ptr)
 50{
 51	return __io_uring_get_cqe(ring, cqe_ptr, 0);
 52}
 53
 54/*
 55 * Return an IO completion, waiting for it if necessary. Returns 0 with
 56 * cqe_ptr filled in on success, -errno on failure.
 57 */
 58int io_uring_wait_cqe(struct io_uring *ring, struct io_uring_cqe **cqe_ptr)
 59{
 60	return __io_uring_get_cqe(ring, cqe_ptr, 1);
 61}
 62
 63/*
 64 * Submit sqes acquired from io_uring_get_sqe() to the kernel.
 65 *
 66 * Returns number of sqes submitted
 67 */
 68int io_uring_submit(struct io_uring *ring)
 69{
 70	struct io_uring_sq *sq = &ring->sq;
 71	const unsigned mask = *sq->kring_mask;
 72	unsigned ktail, ktail_next, submitted, to_submit;
 73	int ret;
 74
 75	/*
 76	 * If we have pending IO in the kring, submit it first. We need a
 77	 * read barrier here to match the kernels store barrier when updating
 78	 * the SQ head.
 79	 */
 80	read_barrier();
 81	if (*sq->khead != *sq->ktail) {
 82		submitted = *sq->kring_entries;
 83		goto submit;
 84	}
 85
 86	if (sq->sqe_head == sq->sqe_tail)
 87		return 0;
 88
 89	/*
 90	 * Fill in sqes that we have queued up, adding them to the kernel ring
 91	 */
 92	submitted = 0;
 93	ktail = ktail_next = *sq->ktail;
 94	to_submit = sq->sqe_tail - sq->sqe_head;
 95	while (to_submit--) {
 96		ktail_next++;
 97		read_barrier();
 98
 99		sq->array[ktail & mask] = sq->sqe_head & mask;
100		ktail = ktail_next;
101
102		sq->sqe_head++;
103		submitted++;
104	}
105
106	if (!submitted)
107		return 0;
108
109	if (*sq->ktail != ktail) {
110		/*
111		 * First write barrier ensures that the SQE stores are updated
112		 * with the tail update. This is needed so that the kernel
113		 * will never see a tail update without the preceeding sQE
114		 * stores being done.
115		 */
116		write_barrier();
117		*sq->ktail = ktail;
118		/*
119		 * The kernel has the matching read barrier for reading the
120		 * SQ tail.
121		 */
122		write_barrier();
123	}
124
125submit:
126	ret = io_uring_enter(ring->ring_fd, submitted, 0,
127				IORING_ENTER_GETEVENTS, NULL);
128	if (ret < 0)
129		return -errno;
130
131	return ret;
132}
133
134/*
135 * Return an sqe to fill. Application must later call io_uring_submit()
136 * when it's ready to tell the kernel about it. The caller may call this
137 * function multiple times before calling io_uring_submit().
138 *
139 * Returns a vacant sqe, or NULL if we're full.
140 */
141struct io_uring_sqe *io_uring_get_sqe(struct io_uring *ring)
142{
143	struct io_uring_sq *sq = &ring->sq;
144	unsigned next = sq->sqe_tail + 1;
145	struct io_uring_sqe *sqe;
146
147	/*
148	 * All sqes are used
149	 */
150	if (next - sq->sqe_head > *sq->kring_entries)
151		return NULL;
152
153	sqe = &sq->sqes[sq->sqe_tail & *sq->kring_mask];
154	sq->sqe_tail = next;
155	return sqe;
156}