read-before-exit.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. #include "../config-host.h"
  2. /* SPDX-License-Identifier: MIT */
  3. /*
  4. * Description: test if issuing IO from thread and immediately exiting will
  5. * proceed correctly.
  6. *
  7. * Original test case from: https://github.com/axboe/liburing/issues/582
  8. */
  9. #include <unistd.h>
  10. #include <pthread.h>
  11. #include <sys/timerfd.h>
  12. #include <string.h>
  13. #include <stdio.h>
  14. #include "liburing.h"
  15. #include "helpers.h"
  16. static int no_iopoll;
  17. struct data {
  18. struct io_uring *ring;
  19. int timer_fd1;
  20. int timer_fd2;
  21. uint64_t buf1;
  22. uint64_t buf2;
  23. };
  24. static void *submit(void *data)
  25. {
  26. struct io_uring_sqe *sqe;
  27. struct data *d = data;
  28. int ret;
  29. sqe = io_uring_get_sqe(d->ring);
  30. io_uring_prep_read(sqe, d->timer_fd1, &d->buf1, sizeof(d->buf1), 0);
  31. sqe = io_uring_get_sqe(d->ring);
  32. io_uring_prep_read(sqe, d->timer_fd2, &d->buf2, sizeof(d->buf2), 0);
  33. ret = io_uring_submit(d->ring);
  34. if (ret != 2) {
  35. struct io_uring_cqe *cqe;
  36. /*
  37. * Kernels without submit-all-on-error behavior will
  38. * fail submitting all, check if that's the case and
  39. * don't error
  40. */
  41. ret = io_uring_peek_cqe(d->ring, &cqe);
  42. if (!ret && cqe->res == -EOPNOTSUPP) {
  43. no_iopoll = 1;
  44. return NULL;
  45. }
  46. return (void *) (uintptr_t) 1;
  47. }
  48. /* Exit suddenly. */
  49. return NULL;
  50. }
  51. static int test(int flags)
  52. {
  53. struct io_uring_params params = { .flags = flags, };
  54. struct io_uring ring;
  55. struct data d = { .ring = &ring, };
  56. pthread_t thread;
  57. void *res;
  58. int ret;
  59. ret = t_create_ring_params(8, &ring, &params);
  60. if (ret == T_SETUP_SKIP)
  61. return 0;
  62. else if (ret != T_SETUP_OK)
  63. return 1;
  64. d.timer_fd1 = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
  65. if (d.timer_fd1 < 0) {
  66. perror("timerfd_create");
  67. return 1;
  68. }
  69. d.timer_fd2 = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
  70. if (d.timer_fd2 < 0) {
  71. perror("timerfd_create");
  72. return 1;
  73. }
  74. pthread_create(&thread, NULL, submit, &d);
  75. pthread_join(thread, &res);
  76. /** Wait for completions and do stuff ... **/
  77. io_uring_queue_exit(&ring);
  78. close(d.timer_fd1);
  79. close(d.timer_fd2);
  80. return !!res;
  81. }
  82. int main(int argc, char *argv[])
  83. {
  84. int ret, i;
  85. for (i = 0; i < 1000; i++) {
  86. ret = test(0);
  87. if (ret) {
  88. fprintf(stderr, "Test failed\n");
  89. return ret;
  90. }
  91. }
  92. for (i = 0; i < 1000; i++) {
  93. ret = test(IORING_SETUP_IOPOLL);
  94. if (ret) {
  95. fprintf(stderr, "Test IOPOLL failed loop %d\n", ret);
  96. return ret;
  97. }
  98. if (no_iopoll)
  99. break;
  100. }
  101. for (i = 0; i < 100; i++) {
  102. ret = test(IORING_SETUP_SQPOLL);
  103. if (ret) {
  104. fprintf(stderr, "Test SQPOLL failed\n");
  105. return ret;
  106. }
  107. }
  108. return 0;
  109. }