• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Description: test if io_uring SQ poll kthread is stopped when the userspace
3  *              process ended with or without closing the io_uring fd
4  *
5  */
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <stdio.h>
9 #include <unistd.h>
10 #include <pthread.h>
11 #include <stdbool.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <signal.h>
15 #include <sys/poll.h>
16 #include <sys/wait.h>
17 #include <sys/epoll.h>
18 
19 #include "liburing.h"
20 
21 #define SQ_THREAD_IDLE  2000
22 #define BUF_SIZE        128
23 #define KTHREAD_NAME    "io_uring-sq"
24 
25 enum {
26 	TEST_OK = 0,
27 	TEST_SKIPPED = 1,
28 	TEST_FAILED = 2,
29 };
30 
do_test_sq_poll_kthread_stopped(bool do_exit)31 static int do_test_sq_poll_kthread_stopped(bool do_exit)
32 {
33 	int ret = 0, pipe1[2];
34 	struct io_uring_params param;
35 	struct io_uring ring;
36 	struct io_uring_sqe *sqe;
37 	struct io_uring_cqe *cqe;
38 	uint8_t buf[BUF_SIZE];
39 	struct iovec iov;
40 
41 	if (geteuid()) {
42 		fprintf(stderr, "sqpoll requires root!\n");
43 		return TEST_SKIPPED;
44 	}
45 
46 	if (pipe(pipe1) != 0) {
47 		perror("pipe");
48 		return TEST_FAILED;
49 	}
50 
51 	memset(&param, 0, sizeof(param));
52 
53 	param.flags |= IORING_SETUP_SQPOLL;
54 	param.sq_thread_idle = SQ_THREAD_IDLE;
55 
56 	ret = io_uring_queue_init_params(16, &ring, &param);
57 	if (ret) {
58 		fprintf(stderr, "ring setup failed\n");
59 		ret = TEST_FAILED;
60 		goto err_pipe;
61 	}
62 
63 	ret = io_uring_register_files(&ring, &pipe1[1], 1);
64 	if (ret) {
65 		fprintf(stderr, "file reg failed: %d\n", ret);
66 		ret = TEST_FAILED;
67 		goto err_uring;
68 	}
69 
70 	iov.iov_base = buf;
71 	iov.iov_len = BUF_SIZE;
72 
73 	sqe = io_uring_get_sqe(&ring);
74 	if (!sqe) {
75 		fprintf(stderr, "io_uring_get_sqe failed\n");
76 		ret = TEST_FAILED;
77 		goto err_uring;
78 	}
79 
80 	io_uring_prep_writev(sqe, 0, &iov, 1, 0);
81 	sqe->flags |= IOSQE_FIXED_FILE;
82 
83 	ret = io_uring_submit(&ring);
84 	if (ret < 0) {
85 		fprintf(stderr, "io_uring_submit failed - ret: %d\n",
86 			ret);
87 		ret = TEST_FAILED;
88 		goto err_uring;
89 	}
90 
91 	ret = io_uring_wait_cqe(&ring, &cqe);
92 	if (ret < 0) {
93 		fprintf(stderr, "io_uring_wait_cqe - ret: %d\n",
94 			ret);
95 		ret = TEST_FAILED;
96 		goto err_uring;
97 	}
98 
99 	if (cqe->res != BUF_SIZE) {
100 		fprintf(stderr, "unexpected cqe->res %d [expected %d]\n",
101 			cqe->res, BUF_SIZE);
102 		ret = TEST_FAILED;
103 		goto err_uring;
104 
105 	}
106 
107 	io_uring_cqe_seen(&ring, cqe);
108 
109 	ret = TEST_OK;
110 
111 err_uring:
112 	if (do_exit)
113 		io_uring_queue_exit(&ring);
114 err_pipe:
115 	close(pipe1[0]);
116 	close(pipe1[1]);
117 
118 	return ret;
119 }
120 
test_sq_poll_kthread_stopped(bool do_exit)121 int test_sq_poll_kthread_stopped(bool do_exit)
122 {
123 	pid_t pid;
124 	int status = 0;
125 
126 	pid = fork();
127 
128 	if (pid == 0) {
129 		int ret = do_test_sq_poll_kthread_stopped(do_exit);
130 		exit(ret);
131 	}
132 
133 	pid = wait(&status);
134 	if (status != 0)
135 		return WEXITSTATUS(status);
136 
137 	sleep(1);
138 	if (system("ps --ppid 2 | grep " KTHREAD_NAME) == 0) {
139 		fprintf(stderr, "%s kthread still running!\n", KTHREAD_NAME);
140 		return TEST_FAILED;
141 	}
142 
143 	return 0;
144 }
145 
main(int argc,char * argv[])146 int main(int argc, char *argv[])
147 {
148 	int ret;
149 
150 	if (argc > 1)
151 		return 0;
152 
153 	ret = test_sq_poll_kthread_stopped(true);
154 	if (ret == TEST_SKIPPED) {
155 		printf("test_sq_poll_kthread_stopped_exit: skipped\n");
156 	} else if (ret == TEST_FAILED) {
157 		fprintf(stderr, "test_sq_poll_kthread_stopped_exit failed\n");
158 		return ret;
159 	}
160 
161 	ret = test_sq_poll_kthread_stopped(false);
162 	if (ret == TEST_SKIPPED) {
163 		printf("test_sq_poll_kthread_stopped_noexit: skipped\n");
164 	} else if (ret == TEST_FAILED) {
165 		fprintf(stderr, "test_sq_poll_kthread_stopped_noexit failed\n");
166 		return ret;
167 	}
168 
169 	return 0;
170 }
171