poll-v-poll.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. #include "../config-host.h"
  2. /* SPDX-License-Identifier: MIT */
  3. /*
  4. * Description: test io_uring poll handling
  5. *
  6. */
  7. #include <errno.h>
  8. #include <stdio.h>
  9. #include <unistd.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <signal.h>
  13. #include <fcntl.h>
  14. #include <poll.h>
  15. #include <sys/wait.h>
  16. #include <sys/select.h>
  17. #include <pthread.h>
  18. #include <sys/epoll.h>
  19. #include "liburing.h"
  20. #include "helpers.h"
  21. struct thread_data {
  22. struct io_uring *ring;
  23. int fd;
  24. int events;
  25. const char *test;
  26. int out[2];
  27. };
  28. static void *epoll_wait_fn(void *data)
  29. {
  30. struct thread_data *td = data;
  31. struct epoll_event ev;
  32. if (epoll_wait(td->fd, &ev, 1, -1) < 0) {
  33. perror("epoll_wait");
  34. goto err;
  35. }
  36. return NULL;
  37. err:
  38. return (void *) 1;
  39. }
  40. static void *iou_poll(void *data)
  41. {
  42. struct thread_data *td = data;
  43. struct io_uring_sqe *sqe;
  44. struct io_uring_cqe *cqe;
  45. int ret;
  46. sqe = io_uring_get_sqe(td->ring);
  47. io_uring_prep_poll_add(sqe, td->fd, td->events);
  48. ret = io_uring_submit(td->ring);
  49. if (ret != 1) {
  50. fprintf(stderr, "submit got %d\n", ret);
  51. goto err;
  52. }
  53. ret = io_uring_wait_cqe(td->ring, &cqe);
  54. if (ret) {
  55. fprintf(stderr, "wait_cqe: %d\n", ret);
  56. goto err;
  57. }
  58. td->out[0] = cqe->res & 0x3f;
  59. io_uring_cqe_seen(td->ring, cqe);
  60. return NULL;
  61. err:
  62. return (void *) 1;
  63. }
  64. static void *poll_pipe(void *data)
  65. {
  66. struct thread_data *td = data;
  67. struct pollfd pfd;
  68. int ret;
  69. pfd.fd = td->fd;
  70. pfd.events = td->events;
  71. ret = poll(&pfd, 1, -1);
  72. if (ret < 0)
  73. perror("poll");
  74. td->out[1] = pfd.revents;
  75. return NULL;
  76. }
  77. static int do_pipe_pollin_test(struct io_uring *ring)
  78. {
  79. struct thread_data td;
  80. pthread_t threads[2];
  81. int ret, pipe1[2];
  82. char buf;
  83. if (pipe(pipe1) < 0) {
  84. perror("pipe");
  85. return 1;
  86. }
  87. td.ring = ring;
  88. td.fd = pipe1[0];
  89. td.events = POLLIN;
  90. td.test = __FUNCTION__;
  91. pthread_create(&threads[1], NULL, iou_poll, &td);
  92. pthread_create(&threads[0], NULL, poll_pipe, &td);
  93. usleep(100000);
  94. buf = 0x89;
  95. ret = write(pipe1[1], &buf, sizeof(buf));
  96. if (ret != sizeof(buf)) {
  97. fprintf(stderr, "write failed: %d\n", ret);
  98. return 1;
  99. }
  100. pthread_join(threads[0], NULL);
  101. pthread_join(threads[1], NULL);
  102. if (td.out[0] != td.out[1]) {
  103. fprintf(stderr, "%s: res %x/%x differ\n", __FUNCTION__,
  104. td.out[0], td.out[1]);
  105. return 1;
  106. }
  107. return 0;
  108. }
  109. static int do_pipe_pollout_test(struct io_uring *ring)
  110. {
  111. struct thread_data td;
  112. pthread_t threads[2];
  113. int ret, pipe1[2];
  114. char buf;
  115. if (pipe(pipe1) < 0) {
  116. perror("pipe");
  117. return 1;
  118. }
  119. td.ring = ring;
  120. td.fd = pipe1[1];
  121. td.events = POLLOUT;
  122. td.test = __FUNCTION__;
  123. pthread_create(&threads[0], NULL, poll_pipe, &td);
  124. pthread_create(&threads[1], NULL, iou_poll, &td);
  125. usleep(100000);
  126. buf = 0x89;
  127. ret = write(pipe1[1], &buf, sizeof(buf));
  128. if (ret != sizeof(buf)) {
  129. fprintf(stderr, "write failed: %d\n", ret);
  130. return 1;
  131. }
  132. pthread_join(threads[0], NULL);
  133. pthread_join(threads[1], NULL);
  134. if (td.out[0] != td.out[1]) {
  135. fprintf(stderr, "%s: res %x/%x differ\n", __FUNCTION__,
  136. td.out[0], td.out[1]);
  137. return 1;
  138. }
  139. return 0;
  140. }
  141. static int do_fd_test(struct io_uring *ring, const char *fname, int events)
  142. {
  143. struct thread_data td;
  144. pthread_t threads[2];
  145. int fd;
  146. fd = open(fname, O_RDONLY);
  147. if (fd < 0) {
  148. if (errno == EPERM || errno == EACCES)
  149. return T_EXIT_SKIP;
  150. perror("open");
  151. return 1;
  152. }
  153. td.ring = ring;
  154. td.fd = fd;
  155. td.events = events;
  156. td.test = __FUNCTION__;
  157. pthread_create(&threads[0], NULL, poll_pipe, &td);
  158. pthread_create(&threads[1], NULL, iou_poll, &td);
  159. pthread_join(threads[0], NULL);
  160. pthread_join(threads[1], NULL);
  161. if (td.out[0] != td.out[1]) {
  162. fprintf(stderr, "%s: res %x/%x differ\n", __FUNCTION__,
  163. td.out[0], td.out[1]);
  164. return 1;
  165. }
  166. return 0;
  167. }
  168. static int iou_epoll_ctl(struct io_uring *ring, int epfd, int fd,
  169. struct epoll_event *ev)
  170. {
  171. struct io_uring_sqe *sqe;
  172. struct io_uring_cqe *cqe;
  173. int ret;
  174. sqe = io_uring_get_sqe(ring);
  175. if (!sqe) {
  176. fprintf(stderr, "Failed to get sqe\n");
  177. return 1;
  178. }
  179. io_uring_prep_epoll_ctl(sqe, epfd, fd, EPOLL_CTL_ADD, ev);
  180. ret = io_uring_submit(ring);
  181. if (ret != 1) {
  182. fprintf(stderr, "submit: %d\n", ret);
  183. return 1;
  184. }
  185. ret = io_uring_wait_cqe(ring, &cqe);
  186. if (ret) {
  187. fprintf(stderr, "wait_cqe: %d\n", ret);
  188. return 1;
  189. }
  190. ret = cqe->res;
  191. io_uring_cqe_seen(ring, cqe);
  192. return ret;
  193. }
  194. static int do_test_epoll(struct io_uring *ring, int iou_epoll_add)
  195. {
  196. struct epoll_event ev;
  197. struct thread_data td;
  198. pthread_t threads[2];
  199. int ret, pipe1[2];
  200. char buf;
  201. int fd;
  202. fd = epoll_create1(0);
  203. if (fd < 0) {
  204. perror("epoll_create");
  205. return 1;
  206. }
  207. if (pipe(pipe1) < 0) {
  208. perror("pipe");
  209. return 1;
  210. }
  211. ev.events = EPOLLIN;
  212. ev.data.fd = pipe1[0];
  213. if (!iou_epoll_add) {
  214. if (epoll_ctl(fd, EPOLL_CTL_ADD, pipe1[0], &ev) < 0) {
  215. perror("epoll_ctrl");
  216. return 1;
  217. }
  218. } else {
  219. ret = iou_epoll_ctl(ring, fd, pipe1[0], &ev);
  220. if (ret == -EINVAL) {
  221. fprintf(stdout, "epoll not supported, skipping\n");
  222. return 0;
  223. } else if (ret < 0) {
  224. return 1;
  225. }
  226. }
  227. td.ring = ring;
  228. td.fd = fd;
  229. td.events = POLLIN;
  230. td.test = __FUNCTION__;
  231. pthread_create(&threads[0], NULL, iou_poll, &td);
  232. pthread_create(&threads[1], NULL, epoll_wait_fn, &td);
  233. usleep(100000);
  234. buf = 0x89;
  235. ret = write(pipe1[1], &buf, sizeof(buf));
  236. if (ret != sizeof(buf)) {
  237. fprintf(stderr, "write failed: %d\n", ret);
  238. return 1;
  239. }
  240. pthread_join(threads[0], NULL);
  241. pthread_join(threads[1], NULL);
  242. return 0;
  243. }
  244. int main(int argc, char *argv[])
  245. {
  246. struct io_uring ring;
  247. const char *fname;
  248. int ret;
  249. ret = io_uring_queue_init(1, &ring, 0);
  250. if (ret) {
  251. fprintf(stderr, "ring setup failed\n");
  252. return 1;
  253. }
  254. ret = do_pipe_pollin_test(&ring);
  255. if (ret) {
  256. fprintf(stderr, "pipe pollin test failed\n");
  257. return ret;
  258. }
  259. ret = do_pipe_pollout_test(&ring);
  260. if (ret) {
  261. fprintf(stderr, "pipe pollout test failed\n");
  262. return ret;
  263. }
  264. ret = do_test_epoll(&ring, 0);
  265. if (ret) {
  266. fprintf(stderr, "epoll test 0 failed\n");
  267. return ret;
  268. }
  269. ret = do_test_epoll(&ring, 1);
  270. if (ret) {
  271. fprintf(stderr, "epoll test 1 failed\n");
  272. return ret;
  273. }
  274. if (argc > 1)
  275. fname = argv[1];
  276. else
  277. fname = argv[0];
  278. ret = do_fd_test(&ring, fname, POLLIN);
  279. if (ret == T_EXIT_FAIL) {
  280. fprintf(stderr, "fd test IN failed\n");
  281. return ret;
  282. }
  283. ret = do_fd_test(&ring, fname, POLLOUT);
  284. if (ret == T_EXIT_FAIL) {
  285. fprintf(stderr, "fd test OUT failed\n");
  286. return ret;
  287. }
  288. ret = do_fd_test(&ring, fname, POLLOUT | POLLIN);
  289. if (ret == T_EXIT_FAIL) {
  290. fprintf(stderr, "fd test IN|OUT failed\n");
  291. return ret;
  292. }
  293. return 0;
  294. }