#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdbool.h>
#include "compat.h"
#include "io_uring.h"
#include "liburing.h"
#include "barrier.h"
int __io_uring_get_cqe(struct io_uring *ring, struct io_uring_cqe **cqe_ptr,
unsigned submit, unsigned wait_nr, sigset_t *sigmask)
{
int ret, err = 0;
do {
err = __io_uring_peek_cqe(ring, cqe_ptr);
if (err || *cqe_ptr)
break;
if (!wait_nr) {
err = -EAGAIN;
break;
}
ret = io_uring_enter(ring->ring_fd, submit, wait_nr,
IORING_ENTER_GETEVENTS, sigmask);
if (ret < 0)
err = -errno;
submit -= ret;
} while (!err);
return err;
}
unsigned io_uring_peek_batch_cqe(struct io_uring *ring,
struct io_uring_cqe **cqes, unsigned count)
{
unsigned ready;
ready = io_uring_cq_ready(ring);
if (ready) {
unsigned head = *ring->cq.khead;
unsigned mask = *ring->cq.kring_mask;
unsigned last;
int i = 0;
count = count > ready ? ready : count;
last = head + count;
for (;head != last; head++, i++)
cqes[i] = &ring->cq.cqes[head & mask];
return count;
}
return 0;
}
static int __io_uring_flush_sq(struct io_uring *ring)
{
struct io_uring_sq *sq = &ring->sq;
const unsigned mask = *sq->kring_mask;
unsigned ktail, submitted, to_submit;
if (sq->sqe_head == sq->sqe_tail)
return 0;
submitted = 0;
ktail = *sq->ktail;
to_submit = sq->sqe_tail - sq->sqe_head;
while (to_submit--) {
sq->array[ktail & mask] = sq->sqe_head & mask;
ktail++;
sq->sqe_head++;
submitted++;
}
if (submitted)
io_uring_smp_store_release(sq->ktail, ktail);
return submitted;
}
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)
{
int ret;
if (wait_nr && ts) {
struct io_uring_sqe *sqe;
sqe = io_uring_get_sqe(ring);
if (!sqe) {
ret = io_uring_submit(ring);
if (ret < 0)
return ret;
sqe = io_uring_get_sqe(ring);
}
io_uring_prep_timeout(sqe, ts, wait_nr);
sqe->user_data = LIBURING_UDATA_TIMEOUT;
}
ret = __io_uring_flush_sq(ring);
return __io_uring_get_cqe(ring, cqe_ptr, ret, wait_nr, sigmask);
}
int io_uring_wait_cqe_timeout(struct io_uring *ring,
struct io_uring_cqe **cqe_ptr,
struct __kernel_timespec *ts)
{
return io_uring_wait_cqes(ring, cqe_ptr, 1, ts, NULL);
}
static inline bool sq_ring_needs_enter(struct io_uring *ring, unsigned *flags)
{
if (!(ring->flags & IORING_SETUP_SQPOLL))
return true;
if ((*ring->sq.kflags & IORING_SQ_NEED_WAKEUP)) {
*flags |= IORING_ENTER_SQ_WAKEUP;
return true;
}
return false;
}
static int __io_uring_submit(struct io_uring *ring, unsigned submitted,
unsigned wait_nr)
{
unsigned flags;
int ret;
flags = 0;
if (wait_nr || sq_ring_needs_enter(ring, &flags)) {
if (wait_nr) {
if (wait_nr > submitted)
wait_nr = submitted;
flags |= IORING_ENTER_GETEVENTS;
}
ret = io_uring_enter(ring->ring_fd, submitted, wait_nr, flags,
NULL);
if (ret < 0)
return -errno;
} else
ret = submitted;
return ret;
}
static int __io_uring_submit_and_wait(struct io_uring *ring, unsigned wait_nr)
{
int submitted;
submitted = __io_uring_flush_sq(ring);
if (submitted)
return __io_uring_submit(ring, submitted, wait_nr);
return 0;
}
int io_uring_submit(struct io_uring *ring)
{
return __io_uring_submit_and_wait(ring, 0);
}
int io_uring_submit_and_wait(struct io_uring *ring, unsigned wait_nr)
{
return __io_uring_submit_and_wait(ring, wait_nr);
}
struct io_uring_sqe *io_uring_get_sqe(struct io_uring *ring)
{
struct io_uring_sq *sq = &ring->sq;
unsigned next = sq->sqe_tail + 1;
struct io_uring_sqe *sqe;
if (next - sq->sqe_head > *sq->kring_entries)
return NULL;
sqe = &sq->sqes[sq->sqe_tail & *sq->kring_mask];
sq->sqe_tail = next;
return sqe;
}