poll-cancel.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. #include "../config-host.h"
  2. /* SPDX-License-Identifier: MIT */
  3. /*
  4. * Description: test io_uring poll cancel 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 <inttypes.h>
  13. #include <poll.h>
  14. #include <sys/wait.h>
  15. #include <signal.h>
  16. #include "liburing.h"
  17. struct poll_data {
  18. unsigned is_poll;
  19. unsigned is_cancel;
  20. };
  21. static void sig_alrm(int sig)
  22. {
  23. fprintf(stderr, "Timed out!\n");
  24. exit(1);
  25. }
  26. static int test_poll_cancel(void)
  27. {
  28. struct io_uring ring;
  29. int pipe1[2];
  30. struct io_uring_cqe *cqe;
  31. struct io_uring_sqe *sqe;
  32. struct poll_data *pd, pds[2];
  33. struct sigaction act;
  34. int ret;
  35. if (pipe(pipe1) != 0) {
  36. perror("pipe");
  37. return 1;
  38. }
  39. ret = io_uring_queue_init(2, &ring, 0);
  40. if (ret) {
  41. fprintf(stderr, "ring setup failed: %d\n", ret);
  42. return 1;
  43. }
  44. memset(&act, 0, sizeof(act));
  45. act.sa_handler = sig_alrm;
  46. act.sa_flags = SA_RESTART;
  47. sigaction(SIGALRM, &act, NULL);
  48. alarm(1);
  49. sqe = io_uring_get_sqe(&ring);
  50. if (!sqe) {
  51. fprintf(stderr, "get sqe failed\n");
  52. return 1;
  53. }
  54. io_uring_prep_poll_add(sqe, pipe1[0], POLLIN);
  55. pds[0].is_poll = 1;
  56. pds[0].is_cancel = 0;
  57. io_uring_sqe_set_data(sqe, &pds[0]);
  58. ret = io_uring_submit(&ring);
  59. if (ret <= 0) {
  60. fprintf(stderr, "sqe submit failed\n");
  61. return 1;
  62. }
  63. sqe = io_uring_get_sqe(&ring);
  64. if (!sqe) {
  65. fprintf(stderr, "get sqe failed\n");
  66. return 1;
  67. }
  68. pds[1].is_poll = 0;
  69. pds[1].is_cancel = 1;
  70. io_uring_prep_poll_remove(sqe, (__u64)(uintptr_t)&pds[0]);
  71. io_uring_sqe_set_data(sqe, &pds[1]);
  72. ret = io_uring_submit(&ring);
  73. if (ret <= 0) {
  74. fprintf(stderr, "sqe submit failed: %d\n", ret);
  75. return 1;
  76. }
  77. ret = io_uring_wait_cqe(&ring, &cqe);
  78. if (ret < 0) {
  79. fprintf(stderr, "wait cqe failed: %d\n", ret);
  80. return 1;
  81. }
  82. pd = io_uring_cqe_get_data(cqe);
  83. if (pd->is_poll && cqe->res != -ECANCELED) {
  84. fprintf(stderr ,"sqe (add=%d/remove=%d) failed with %ld\n",
  85. pd->is_poll, pd->is_cancel,
  86. (long) cqe->res);
  87. return 1;
  88. } else if (pd->is_cancel && cqe->res) {
  89. fprintf(stderr, "sqe (add=%d/remove=%d) failed with %ld\n",
  90. pd->is_poll, pd->is_cancel,
  91. (long) cqe->res);
  92. return 1;
  93. }
  94. io_uring_cqe_seen(&ring, cqe);
  95. ret = io_uring_wait_cqe(&ring, &cqe);
  96. if (ret < 0) {
  97. fprintf(stderr, "wait_cqe: %d\n", ret);
  98. return 1;
  99. }
  100. pd = io_uring_cqe_get_data(cqe);
  101. if (pd->is_poll && cqe->res != -ECANCELED) {
  102. fprintf(stderr, "sqe (add=%d/remove=%d) failed with %ld\n",
  103. pd->is_poll, pd->is_cancel,
  104. (long) cqe->res);
  105. return 1;
  106. } else if (pd->is_cancel && cqe->res) {
  107. fprintf(stderr, "sqe (add=%d/remove=%d) failed with %ld\n",
  108. pd->is_poll, pd->is_cancel,
  109. (long) cqe->res);
  110. return 1;
  111. }
  112. close(pipe1[0]);
  113. close(pipe1[1]);
  114. io_uring_cqe_seen(&ring, cqe);
  115. io_uring_queue_exit(&ring);
  116. return 0;
  117. }
  118. static int __test_poll_cancel_with_timeouts(void)
  119. {
  120. struct __kernel_timespec ts = { .tv_sec = 10, };
  121. struct io_uring ring, ring2;
  122. struct io_uring_sqe *sqe;
  123. int ret, off_nr = 1000;
  124. ret = io_uring_queue_init(8, &ring, 0);
  125. if (ret) {
  126. fprintf(stderr, "ring setup failed: %d\n", ret);
  127. return 1;
  128. }
  129. ret = io_uring_queue_init(1, &ring2, 0);
  130. if (ret) {
  131. fprintf(stderr, "ring setup failed: %d\n", ret);
  132. return 1;
  133. }
  134. /* test timeout-offset triggering path during cancellation */
  135. sqe = io_uring_get_sqe(&ring);
  136. io_uring_prep_timeout(sqe, &ts, off_nr, 0);
  137. /* poll ring2 to trigger cancellation on exit() */
  138. sqe = io_uring_get_sqe(&ring);
  139. io_uring_prep_poll_add(sqe, ring2.ring_fd, POLLIN);
  140. sqe->flags |= IOSQE_IO_LINK;
  141. sqe = io_uring_get_sqe(&ring);
  142. io_uring_prep_link_timeout(sqe, &ts, 0);
  143. ret = io_uring_submit(&ring);
  144. if (ret != 3) {
  145. fprintf(stderr, "sqe submit failed\n");
  146. return 1;
  147. }
  148. /* just drop all rings/etc. intact, exit() will clean them up */
  149. return 0;
  150. }
  151. static int test_poll_cancel_with_timeouts(void)
  152. {
  153. int ret;
  154. pid_t p;
  155. p = fork();
  156. if (p == -1) {
  157. fprintf(stderr, "fork() failed\n");
  158. return 1;
  159. }
  160. if (p == 0) {
  161. ret = __test_poll_cancel_with_timeouts();
  162. exit(ret);
  163. } else {
  164. int wstatus;
  165. if (waitpid(p, &wstatus, 0) == (pid_t)-1) {
  166. perror("waitpid()");
  167. return 1;
  168. }
  169. if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus)) {
  170. fprintf(stderr, "child failed %i\n", WEXITSTATUS(wstatus));
  171. return 1;
  172. }
  173. }
  174. return 0;
  175. }
  176. int main(int argc, char *argv[])
  177. {
  178. int ret;
  179. if (argc > 1)
  180. return 0;
  181. ret = test_poll_cancel();
  182. if (ret) {
  183. fprintf(stderr, "test_poll_cancel failed\n");
  184. return -1;
  185. }
  186. ret = test_poll_cancel_with_timeouts();
  187. if (ret) {
  188. fprintf(stderr, "test_poll_cancel_with_timeouts failed\n");
  189. return -1;
  190. }
  191. return 0;
  192. }