exit-no-cleanup.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. #include "../config-host.h"
  2. /* SPDX-License-Identifier: MIT */
  3. /*
  4. * Test case testing exit without cleanup and io-wq work pending or queued.
  5. *
  6. * From Florian Fischer <florian.fl.fischer@fau.de>
  7. * Link: https://lore.kernel.org/io-uring/20211202165606.mqryio4yzubl7ms5@pasture/
  8. *
  9. */
  10. #include <assert.h>
  11. #include <err.h>
  12. #include <errno.h>
  13. #include <pthread.h>
  14. #include <semaphore.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <sys/sysinfo.h>
  18. #include <unistd.h>
  19. #include "liburing.h"
  20. #include "helpers.h"
  21. #define IORING_ENTRIES 8
  22. static pthread_t *threads;
  23. static pthread_barrier_t init_barrier;
  24. static int sleep_fd, notify_fd;
  25. static sem_t sem;
  26. static void *thread_func(void *arg)
  27. {
  28. struct io_uring ring;
  29. int res;
  30. res = io_uring_queue_init(IORING_ENTRIES, &ring, 0);
  31. if (res)
  32. err(EXIT_FAILURE, "io_uring_queue_init failed");
  33. pthread_barrier_wait(&init_barrier);
  34. for(;;) {
  35. struct io_uring_cqe *cqe;
  36. struct io_uring_sqe *sqe;
  37. uint64_t buf;
  38. int res;
  39. sqe = io_uring_get_sqe(&ring);
  40. assert(sqe);
  41. io_uring_prep_read(sqe, sleep_fd, &buf, sizeof(buf), 0);
  42. res = io_uring_submit_and_wait(&ring, 1);
  43. if (res < 0)
  44. err(EXIT_FAILURE, "io_uring_submit_and_wait failed");
  45. res = io_uring_peek_cqe(&ring, &cqe);
  46. assert(!res);
  47. if (cqe->res < 0) {
  48. errno = -cqe->res;
  49. err(EXIT_FAILURE, "read failed");
  50. }
  51. assert(cqe->res == sizeof(buf));
  52. sem_post(&sem);
  53. io_uring_cqe_seen(&ring, cqe);
  54. }
  55. return NULL;
  56. }
  57. int main(int argc, char *argv[])
  58. {
  59. int res, fds[2], i, cpus;
  60. const uint64_t n = 0x42;
  61. if (argc > 1)
  62. return T_EXIT_SKIP;
  63. cpus = get_nprocs();
  64. res = pthread_barrier_init(&init_barrier, NULL, cpus);
  65. if (res)
  66. err(EXIT_FAILURE, "pthread_barrier_init failed");
  67. res = sem_init(&sem, 0, 0);
  68. if (res)
  69. err(EXIT_FAILURE, "sem_init failed");
  70. threads = t_malloc(sizeof(pthread_t) * cpus);
  71. res = pipe(fds);
  72. if (res)
  73. err(EXIT_FAILURE, "pipe failed");
  74. sleep_fd = fds[0];
  75. notify_fd = fds[1];
  76. for (i = 0; i < cpus; i++) {
  77. errno = pthread_create(&threads[i], NULL, thread_func, NULL);
  78. if (errno)
  79. err(EXIT_FAILURE, "pthread_create failed");
  80. }
  81. // Write #cpus notifications
  82. for (i = 0; i < cpus; i++) {
  83. res = write(notify_fd, &n, sizeof(n));
  84. if (res < 0)
  85. err(EXIT_FAILURE, "write failed");
  86. assert(res == sizeof(n));
  87. }
  88. // Await that all notifications were received
  89. for (i = 0; i < cpus; i++)
  90. sem_wait(&sem);
  91. // Exit without resource cleanup
  92. exit(EXIT_SUCCESS);
  93. }