mini_liburing.h 7.3 KB

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