Path: blob/master/tools/include/io_uring/mini_liburing.h
26285 views
/* SPDX-License-Identifier: MIT */12#include <linux/io_uring.h>3#include <sys/mman.h>4#include <sys/syscall.h>5#include <stdio.h>6#include <string.h>7#include <unistd.h>89struct io_sq_ring {10unsigned int *head;11unsigned int *tail;12unsigned int *ring_mask;13unsigned int *ring_entries;14unsigned int *flags;15unsigned int *array;16};1718struct io_cq_ring {19unsigned int *head;20unsigned int *tail;21unsigned int *ring_mask;22unsigned int *ring_entries;23struct io_uring_cqe *cqes;24};2526struct io_uring_sq {27unsigned int *khead;28unsigned int *ktail;29unsigned int *kring_mask;30unsigned int *kring_entries;31unsigned int *kflags;32unsigned int *kdropped;33unsigned int *array;34struct io_uring_sqe *sqes;3536unsigned int sqe_head;37unsigned int sqe_tail;3839size_t ring_sz;40};4142struct io_uring_cq {43unsigned int *khead;44unsigned int *ktail;45unsigned int *kring_mask;46unsigned int *kring_entries;47unsigned int *koverflow;48struct io_uring_cqe *cqes;4950size_t ring_sz;51};5253struct io_uring {54struct io_uring_sq sq;55struct io_uring_cq cq;56int ring_fd;57};5859#if defined(__x86_64) || defined(__i386__)60#define read_barrier() __asm__ __volatile__("":::"memory")61#define write_barrier() __asm__ __volatile__("":::"memory")62#else63#define read_barrier() __sync_synchronize()64#define write_barrier() __sync_synchronize()65#endif6667static inline int io_uring_mmap(int fd, struct io_uring_params *p,68struct io_uring_sq *sq, struct io_uring_cq *cq)69{70size_t size;71void *ptr;72int ret;7374sq->ring_sz = p->sq_off.array + p->sq_entries * sizeof(unsigned int);75ptr = mmap(0, sq->ring_sz, PROT_READ | PROT_WRITE,76MAP_SHARED | MAP_POPULATE, fd, IORING_OFF_SQ_RING);77if (ptr == MAP_FAILED)78return -errno;79sq->khead = ptr + p->sq_off.head;80sq->ktail = ptr + p->sq_off.tail;81sq->kring_mask = ptr + p->sq_off.ring_mask;82sq->kring_entries = ptr + p->sq_off.ring_entries;83sq->kflags = ptr + p->sq_off.flags;84sq->kdropped = ptr + p->sq_off.dropped;85sq->array = ptr + p->sq_off.array;8687size = p->sq_entries * sizeof(struct io_uring_sqe);88sq->sqes = mmap(0, size, PROT_READ | PROT_WRITE,89MAP_SHARED | MAP_POPULATE, fd, IORING_OFF_SQES);90if (sq->sqes == MAP_FAILED) {91ret = -errno;92err:93munmap(sq->khead, sq->ring_sz);94return ret;95}9697cq->ring_sz = p->cq_off.cqes + p->cq_entries * sizeof(struct io_uring_cqe);98ptr = mmap(0, cq->ring_sz, PROT_READ | PROT_WRITE,99MAP_SHARED | MAP_POPULATE, fd, IORING_OFF_CQ_RING);100if (ptr == MAP_FAILED) {101ret = -errno;102munmap(sq->sqes, p->sq_entries * sizeof(struct io_uring_sqe));103goto err;104}105cq->khead = ptr + p->cq_off.head;106cq->ktail = ptr + p->cq_off.tail;107cq->kring_mask = ptr + p->cq_off.ring_mask;108cq->kring_entries = ptr + p->cq_off.ring_entries;109cq->koverflow = ptr + p->cq_off.overflow;110cq->cqes = ptr + p->cq_off.cqes;111return 0;112}113114static inline int io_uring_setup(unsigned int entries,115struct io_uring_params *p)116{117return syscall(__NR_io_uring_setup, entries, p);118}119120static inline int io_uring_enter(int fd, unsigned int to_submit,121unsigned int min_complete,122unsigned int flags, sigset_t *sig)123{124return syscall(__NR_io_uring_enter, fd, to_submit, min_complete,125flags, sig, _NSIG / 8);126}127128static inline int io_uring_queue_init(unsigned int entries,129struct io_uring *ring,130unsigned int flags)131{132struct io_uring_params p;133int fd, ret;134135memset(ring, 0, sizeof(*ring));136memset(&p, 0, sizeof(p));137p.flags = flags;138139fd = io_uring_setup(entries, &p);140if (fd < 0)141return fd;142ret = io_uring_mmap(fd, &p, &ring->sq, &ring->cq);143if (!ret)144ring->ring_fd = fd;145else146close(fd);147return ret;148}149150/* Get a sqe */151static inline struct io_uring_sqe *io_uring_get_sqe(struct io_uring *ring)152{153struct io_uring_sq *sq = &ring->sq;154155if (sq->sqe_tail + 1 - sq->sqe_head > *sq->kring_entries)156return NULL;157return &sq->sqes[sq->sqe_tail++ & *sq->kring_mask];158}159160static inline int io_uring_wait_cqe(struct io_uring *ring,161struct io_uring_cqe **cqe_ptr)162{163struct io_uring_cq *cq = &ring->cq;164const unsigned int mask = *cq->kring_mask;165unsigned int head = *cq->khead;166int ret;167168*cqe_ptr = NULL;169do {170read_barrier();171if (head != *cq->ktail) {172*cqe_ptr = &cq->cqes[head & mask];173break;174}175ret = io_uring_enter(ring->ring_fd, 0, 1,176IORING_ENTER_GETEVENTS, NULL);177if (ret < 0)178return -errno;179} while (1);180181return 0;182}183184static inline int io_uring_submit(struct io_uring *ring)185{186struct io_uring_sq *sq = &ring->sq;187const unsigned int mask = *sq->kring_mask;188unsigned int ktail, submitted, to_submit;189int ret;190191read_barrier();192if (*sq->khead != *sq->ktail) {193submitted = *sq->kring_entries;194goto submit;195}196if (sq->sqe_head == sq->sqe_tail)197return 0;198199ktail = *sq->ktail;200to_submit = sq->sqe_tail - sq->sqe_head;201for (submitted = 0; submitted < to_submit; submitted++) {202read_barrier();203sq->array[ktail++ & mask] = sq->sqe_head++ & mask;204}205if (!submitted)206return 0;207208if (*sq->ktail != ktail) {209write_barrier();210*sq->ktail = ktail;211write_barrier();212}213submit:214ret = io_uring_enter(ring->ring_fd, submitted, 0,215IORING_ENTER_GETEVENTS, NULL);216return ret < 0 ? -errno : ret;217}218219static inline void io_uring_queue_exit(struct io_uring *ring)220{221struct io_uring_sq *sq = &ring->sq;222223munmap(sq->sqes, *sq->kring_entries * sizeof(struct io_uring_sqe));224munmap(sq->khead, sq->ring_sz);225close(ring->ring_fd);226}227228/* Prepare and send the SQE */229static inline void io_uring_prep_cmd(struct io_uring_sqe *sqe, int op,230int sockfd,231int level, int optname,232const void *optval,233int optlen)234{235memset(sqe, 0, sizeof(*sqe));236sqe->opcode = (__u8)IORING_OP_URING_CMD;237sqe->fd = sockfd;238sqe->cmd_op = op;239240sqe->level = level;241sqe->optname = optname;242sqe->optval = (unsigned long long)optval;243sqe->optlen = optlen;244}245246static inline int io_uring_register_buffers(struct io_uring *ring,247const struct iovec *iovecs,248unsigned int nr_iovecs)249{250int ret;251252ret = syscall(__NR_io_uring_register, ring->ring_fd,253IORING_REGISTER_BUFFERS, iovecs, nr_iovecs);254return (ret < 0) ? -errno : ret;255}256257static inline void io_uring_prep_send(struct io_uring_sqe *sqe, int sockfd,258const void *buf, size_t len, int flags)259{260memset(sqe, 0, sizeof(*sqe));261sqe->opcode = (__u8)IORING_OP_SEND;262sqe->fd = sockfd;263sqe->addr = (unsigned long)buf;264sqe->len = len;265sqe->msg_flags = (__u32)flags;266}267268static inline void io_uring_prep_sendzc(struct io_uring_sqe *sqe, int sockfd,269const void *buf, size_t len, int flags,270unsigned int zc_flags)271{272io_uring_prep_send(sqe, sockfd, buf, len, flags);273sqe->opcode = (__u8)IORING_OP_SEND_ZC;274sqe->ioprio = zc_flags;275}276277static inline void io_uring_cqe_seen(struct io_uring *ring)278{279*(&ring->cq)->khead += 1;280write_barrier();281}282283284