files-exit-hang-timeout.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #include "../config-host.h"
  2. /* SPDX-License-Identifier: MIT */
  3. /*
  4. * Based on a test case from Josef Grieb - test that we can exit without
  5. * hanging if we have the task file table pinned by a request that is linked
  6. * to another request that doesn't finish.
  7. */
  8. #include <errno.h>
  9. #include <fcntl.h>
  10. #include <netinet/in.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <strings.h>
  15. #include <sys/socket.h>
  16. #include <unistd.h>
  17. #include <poll.h>
  18. #include "liburing.h"
  19. #include "helpers.h"
  20. #define BACKLOG 512
  21. #define PORT 9100
  22. static struct io_uring ring;
  23. static struct __kernel_timespec ts = {
  24. .tv_sec = 300,
  25. .tv_nsec = 0,
  26. };
  27. static void add_timeout(struct io_uring *ring, int fd)
  28. {
  29. struct io_uring_sqe *sqe;
  30. sqe = io_uring_get_sqe(ring);
  31. io_uring_prep_timeout(sqe, &ts, 100, 0);
  32. sqe->flags |= IOSQE_IO_LINK;
  33. }
  34. static void add_accept(struct io_uring *ring, int fd)
  35. {
  36. struct io_uring_sqe *sqe;
  37. sqe = io_uring_get_sqe(ring);
  38. io_uring_prep_accept(sqe, fd, 0, 0, SOCK_NONBLOCK | SOCK_CLOEXEC);
  39. sqe->flags |= IOSQE_IO_LINK;
  40. }
  41. static int setup_io_uring(void)
  42. {
  43. int ret;
  44. ret = io_uring_queue_init(16, &ring, 0);
  45. if (ret) {
  46. fprintf(stderr, "Unable to setup io_uring: %s\n", strerror(-ret));
  47. return 1;
  48. }
  49. return 0;
  50. }
  51. static void alarm_sig(int sig)
  52. {
  53. exit(0);
  54. }
  55. int main(int argc, char *argv[])
  56. {
  57. struct sockaddr_in serv_addr;
  58. struct io_uring_cqe *cqe;
  59. int ret, sock_listen_fd;
  60. const int val = 1;
  61. int i;
  62. if (argc > 1)
  63. return T_EXIT_SKIP;
  64. sock_listen_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
  65. if (sock_listen_fd < 0) {
  66. perror("socket");
  67. return T_EXIT_FAIL;
  68. }
  69. setsockopt(sock_listen_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
  70. memset(&serv_addr, 0, sizeof(serv_addr));
  71. serv_addr.sin_family = AF_INET;
  72. serv_addr.sin_addr.s_addr = INADDR_ANY;
  73. for (i = 0; i < 100; i++) {
  74. serv_addr.sin_port = htons(PORT + i);
  75. ret = bind(sock_listen_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
  76. if (!ret)
  77. break;
  78. if (errno != EADDRINUSE) {
  79. fprintf(stderr, "bind: %s\n", strerror(errno));
  80. return T_EXIT_FAIL;
  81. }
  82. if (i == 99) {
  83. printf("Gave up on finding a port, skipping\n");
  84. goto skip;
  85. }
  86. }
  87. if (listen(sock_listen_fd, BACKLOG) < 0) {
  88. perror("Error listening on socket\n");
  89. return T_EXIT_FAIL;
  90. }
  91. if (setup_io_uring())
  92. return T_EXIT_FAIL;
  93. add_timeout(&ring, sock_listen_fd);
  94. add_accept(&ring, sock_listen_fd);
  95. ret = io_uring_submit(&ring);
  96. if (ret != 2) {
  97. fprintf(stderr, "submit=%d\n", ret);
  98. return T_EXIT_FAIL;
  99. }
  100. signal(SIGALRM, alarm_sig);
  101. alarm(1);
  102. ret = io_uring_wait_cqe(&ring, &cqe);
  103. if (ret) {
  104. fprintf(stderr, "wait_cqe=%d\n", ret);
  105. return T_EXIT_FAIL;
  106. }
  107. io_uring_queue_exit(&ring);
  108. return T_EXIT_PASS;
  109. skip:
  110. io_uring_queue_exit(&ring);
  111. return T_EXIT_SKIP;
  112. }