mini_liburing.h 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /* SPDX-License-Identifier: MIT */
  2. #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>
  8. struct io_sq_ring {
  9. unsigned int *head;
  10. unsigned int *tail;
  11. unsigned int *ring_mask;
  12. unsigned int *ring_entries;
  13. unsigned int *flags;
  14. unsigned int *array;
  15. };
  16. struct io_cq_ring {
  17. unsigned int *head;
  18. unsigned int *tail;
  19. unsigned int *ring_mask;
  20. unsigned int *ring_entries;
  21. struct io_uring_cqe *cqes;
  22. };
  23. struct io_uring_sq {
  24. unsigned int *khead;
  25. unsigned int *ktail;
  26. unsigned int *kring_mask;
  27. unsigned int *kring_entries;
  28. unsigned int *kflags;
  29. unsigned int *kdropped;
  30. unsigned int *array;
  31. struct io_uring_sqe *sqes;
  32. unsigned int sqe_head;
  33. unsigned int sqe_tail;
  34. size_t ring_sz;
  35. };
  36. struct io_uring_cq {
  37. unsigned int *khead;
  38. unsigned int *ktail;
  39. unsigned int *kring_mask;
  40. unsigned int *kring_entries;
  41. unsigned int *koverflow;
  42. struct io_uring_cqe *cqes;
  43. size_t ring_sz;
  44. };
  45. struct io_uring {
  46. struct io_uring_sq sq;
  47. struct io_uring_cq cq;
  48. int ring_fd;
  49. };
  50. #if defined(__x86_64) || defined(__i386__)
  51. #define read_barrier() __asm__ __volatile__("":::"memory")
  52. #define write_barrier() __asm__ __volatile__("":::"memory")
  53. #else
  54. #define read_barrier() __sync_synchronize()
  55. #define write_barrier() __sync_synchronize()
  56. #endif
  57. static inline int io_uring_mmap(int fd, struct io_uring_params *p,
  58. struct io_uring_sq *sq, struct io_uring_cq *cq)
  59. {
  60. size_t size;
  61. void *ptr;
  62. int ret;
  63. sq->ring_sz = p->sq_off.array + p->sq_entries * sizeof(unsigned int);
  64. ptr = mmap(0, sq->ring_sz, PROT_READ | PROT_WRITE,
  65. MAP_SHARED | MAP_POPULATE, fd, IORING_OFF_SQ_RING);
  66. if (ptr == MAP_FAILED)
  67. return -errno;
  68. sq->khead = ptr + p->sq_off.head;
  69. sq->ktail = ptr + p->sq_off.tail;
  70. sq->kring_mask = ptr + p->sq_off.ring_mask;
  71. sq->kring_entries = ptr + p->sq_off.ring_entries;
  72. sq->kflags = ptr + p->sq_off.flags;
  73. sq->kdropped = ptr + p->sq_off.dropped;
  74. sq->array = ptr + p->sq_off.array;
  75. size = p->sq_entries * sizeof(struct io_uring_sqe);
  76. sq->sqes = mmap(0, size, PROT_READ | PROT_WRITE,
  77. MAP_SHARED | MAP_POPULATE, fd, IORING_OFF_SQES);
  78. if (sq->sqes == MAP_FAILED) {
  79. ret = -errno;
  80. err:
  81. munmap(sq->khead, sq->ring_sz);
  82. return ret;
  83. }
  84. cq->ring_sz = p->cq_off.cqes + p->cq_entries * sizeof(struct io_uring_cqe);
  85. ptr = mmap(0, cq->ring_sz, PROT_READ | PROT_WRITE,
  86. MAP_SHARED | MAP_POPULATE, fd, IORING_OFF_CQ_RING);
  87. if (ptr == MAP_FAILED) {
  88. ret = -errno;
  89. munmap(sq->sqes, p->sq_entries * sizeof(struct io_uring_sqe));
  90. goto err;
  91. }
  92. cq->khead = ptr + p->cq_off.head;
  93. cq->ktail = ptr + p->cq_off.tail;
  94. cq->kring_mask = ptr + p->cq_off.ring_mask;
  95. cq->kring_entries = ptr + p->cq_off.ring_entries;
  96. cq->koverflow = ptr + p->cq_off.overflow;
  97. cq->cqes = ptr + p->cq_off.cqes;
  98. return 0;
  99. }
  100. static inline int io_uring_setup(unsigned int entries,
  101. struct io_uring_params *p)
  102. {
  103. return syscall(__NR_io_uring_setup, entries, p);
  104. }
  105. static inline int io_uring_enter(int fd, unsigned int to_submit,
  106. unsigned int min_complete,
  107. unsigned int flags, sigset_t *sig)
  108. {
  109. return syscall(__NR_io_uring_enter, fd, to_submit, min_complete,
  110. flags, sig, _NSIG / 8);
  111. }
  112. static inline int io_uring_queue_init(unsigned int entries,
  113. struct io_uring *ring,
  114. unsigned int flags)
  115. {
  116. struct io_uring_params p;
  117. int fd, ret;
  118. memset(ring, 0, sizeof(*ring));
  119. memset(&p, 0, sizeof(p));
  120. p.flags = flags;
  121. fd = io_uring_setup(entries, &p);
  122. if (fd < 0)
  123. return fd;
  124. ret = io_uring_mmap(fd, &p, &ring->sq, &ring->cq);
  125. if (!ret)
  126. ring->ring_fd = fd;
  127. else
  128. close(fd);
  129. return ret;
  130. }
  131. /* Get a sqe */
  132. static inline struct io_uring_sqe *io_uring_get_sqe(struct io_uring *ring)
  133. {
  134. struct io_uring_sq *sq = &ring->sq;
  135. if (sq->sqe_tail + 1 - sq->sqe_head > *sq->kring_entries)
  136. return NULL;
  137. return &sq->sqes[sq->sqe_tail++ & *sq->kring_mask];
  138. }
  139. static inline int io_uring_wait_cqe(struct io_uring *ring,
  140. struct io_uring_cqe **cqe_ptr)
  141. {
  142. struct io_uring_cq *cq = &ring->cq;
  143. const unsigned int mask = *cq->kring_mask;
  144. unsigned int head = *cq->khead;
  145. int ret;
  146. *cqe_ptr = NULL;
  147. do {
  148. read_barrier();
  149. if (head != *cq->ktail) {
  150. *cqe_ptr = &cq->cqes[head & mask];
  151. break;
  152. }
  153. ret = io_uring_enter(ring->ring_fd, 0, 1,
  154. IORING_ENTER_GETEVENTS, NULL);
  155. if (ret < 0)
  156. return -errno;
  157. } while (1);
  158. return 0;
  159. }
  160. static inline int io_uring_submit(struct io_uring *ring)
  161. {
  162. struct io_uring_sq *sq = &ring->sq;
  163. const unsigned int mask = *sq->kring_mask;
  164. unsigned int ktail, submitted, to_submit;
  165. int ret;
  166. read_barrier();
  167. if (*sq->khead != *sq->ktail) {
  168. submitted = *sq->kring_entries;
  169. goto submit;
  170. }
  171. if (sq->sqe_head == sq->sqe_tail)
  172. return 0;
  173. ktail = *sq->ktail;
  174. to_submit = sq->sqe_tail - sq->sqe_head;
  175. for (submitted = 0; submitted < to_submit; submitted++) {
  176. read_barrier();
  177. sq->array[ktail++ & mask] = sq->sqe_head++ & mask;
  178. }
  179. if (!submitted)
  180. return 0;
  181. if (*sq->ktail != ktail) {
  182. write_barrier();
  183. *sq->ktail = ktail;
  184. write_barrier();
  185. }
  186. submit:
  187. ret = io_uring_enter(ring->ring_fd, submitted, 0,
  188. IORING_ENTER_GETEVENTS, NULL);
  189. return ret < 0 ? -errno : ret;
  190. }
  191. static inline void io_uring_queue_exit(struct io_uring *ring)
  192. {
  193. struct io_uring_sq *sq = &ring->sq;
  194. munmap(sq->sqes, *sq->kring_entries * sizeof(struct io_uring_sqe));
  195. munmap(sq->khead, sq->ring_sz);
  196. close(ring->ring_fd);
  197. }
  198. /* Prepare and send the SQE */
  199. static inline void io_uring_prep_cmd(struct io_uring_sqe *sqe, int op,
  200. int sockfd,
  201. int level, int optname,
  202. const void *optval,
  203. int optlen)
  204. {
  205. memset(sqe, 0, sizeof(*sqe));
  206. sqe->opcode = (__u8)IORING_OP_URING_CMD;
  207. sqe->fd = sockfd;
  208. sqe->cmd_op = op;
  209. sqe->level = level;
  210. sqe->optname = optname;
  211. sqe->optval = (unsigned long long)optval;
  212. sqe->optlen = optlen;
  213. }
  214. static inline int io_uring_register_buffers(struct io_uring *ring,
  215. const struct iovec *iovecs,
  216. unsigned int nr_iovecs)
  217. {
  218. int ret;
  219. ret = syscall(__NR_io_uring_register, ring->ring_fd,
  220. IORING_REGISTER_BUFFERS, iovecs, nr_iovecs);
  221. return (ret < 0) ? -errno : ret;
  222. }
  223. static inline void io_uring_prep_send(struct io_uring_sqe *sqe, int sockfd,
  224. const void *buf, size_t len, int flags)
  225. {
  226. memset(sqe, 0, sizeof(*sqe));
  227. sqe->opcode = (__u8)IORING_OP_SEND;
  228. sqe->fd = sockfd;
  229. sqe->addr = (unsigned long)buf;
  230. sqe->len = len;
  231. sqe->msg_flags = (__u32)flags;
  232. }
  233. static inline void io_uring_prep_sendzc(struct io_uring_sqe *sqe, int sockfd,
  234. const void *buf, size_t len, int flags,
  235. unsigned int zc_flags)
  236. {
  237. io_uring_prep_send(sqe, sockfd, buf, len, flags);
  238. sqe->opcode = (__u8)IORING_OP_SEND_ZC;
  239. sqe->ioprio = zc_flags;
  240. }
  241. static inline void io_uring_cqe_seen(struct io_uring *ring)
  242. {
  243. *(&ring->cq)->khead += 1;
  244. write_barrier();
  245. }