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