files-exit-hang-timeout.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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. }
  40. static int setup_io_uring(void)
  41. {
  42. int ret;
  43. ret = io_uring_queue_init(16, &ring, 0);
  44. if (ret) {
  45. fprintf(stderr, "Unable to setup io_uring: %s\n", strerror(-ret));
  46. return 1;
  47. }
  48. return 0;
  49. }
  50. static void alarm_sig(int sig)
  51. {
  52. exit(0);
  53. }
  54. int main(int argc, char *argv[])
  55. {
  56. struct sockaddr_in serv_addr;
  57. struct io_uring_cqe *cqe;
  58. int ret, sock_listen_fd;
  59. const int val = 1;
  60. int i;
  61. if (argc > 1)
  62. return T_EXIT_SKIP;
  63. sock_listen_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
  64. if (sock_listen_fd < 0) {
  65. perror("socket");
  66. return T_EXIT_FAIL;
  67. }
  68. setsockopt(sock_listen_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
  69. memset(&serv_addr, 0, sizeof(serv_addr));
  70. serv_addr.sin_family = AF_INET;
  71. serv_addr.sin_addr.s_addr = INADDR_ANY;
  72. for (i = 0; i < 100; i++) {
  73. serv_addr.sin_port = htons(PORT + i);
  74. ret = bind(sock_listen_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
  75. if (!ret)
  76. break;
  77. if (errno != EADDRINUSE) {
  78. fprintf(stderr, "bind: %s\n", strerror(errno));
  79. return T_EXIT_FAIL;
  80. }
  81. if (i == 99) {
  82. printf("Gave up on finding a port, skipping\n");
  83. goto skip;
  84. }
  85. }
  86. if (listen(sock_listen_fd, BACKLOG) < 0) {
  87. perror("Error listening on socket\n");
  88. return T_EXIT_FAIL;
  89. }
  90. if (setup_io_uring())
  91. return T_EXIT_FAIL;
  92. add_timeout(&ring, sock_listen_fd);
  93. add_accept(&ring, sock_listen_fd);
  94. ret = io_uring_submit(&ring);
  95. if (ret != 2) {
  96. fprintf(stderr, "submit=%d\n", ret);
  97. return T_EXIT_FAIL;
  98. }
  99. signal(SIGALRM, alarm_sig);
  100. alarm(1);
  101. ret = io_uring_wait_cqe(&ring, &cqe);
  102. if (ret) {
  103. fprintf(stderr, "wait_cqe=%d\n", ret);
  104. return T_EXIT_FAIL;
  105. }
  106. io_uring_queue_exit(&ring);
  107. return T_EXIT_PASS;
  108. skip:
  109. io_uring_queue_exit(&ring);
  110. return T_EXIT_SKIP;
  111. }