• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: MIT */
2 /*
3  * Description: Test IORING_ASYNC_CANCEL_{ALL,FD}
4  *
5  */
6 #include <errno.h>
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <poll.h>
12 
13 #include "liburing.h"
14 
15 static int no_cancel_flags;
16 
test1(struct io_uring * ring,int * fd)17 static int test1(struct io_uring *ring, int *fd)
18 {
19 	struct io_uring_sqe *sqe;
20 	struct io_uring_cqe *cqe;
21 	int ret, i;
22 
23 	for (i = 0; i < 8; i++) {
24 		sqe = io_uring_get_sqe(ring);
25 		if (!sqe) {
26 			fprintf(stderr, "get sqe failed\n");
27 			return 1;
28 		}
29 
30 		io_uring_prep_poll_add(sqe, fd[0], POLLIN);
31 		sqe->user_data = i + 1;
32 	}
33 
34 	ret = io_uring_submit(ring);
35 	if (ret < 8) {
36 		fprintf(stderr, "sqe submit failed: %d\n", ret);
37 		return 1;
38 	}
39 
40 	sqe = io_uring_get_sqe(ring);
41 	if (!sqe) {
42 		fprintf(stderr, "get sqe failed\n");
43 		return 1;
44 	}
45 
46 	/*
47 	 * Mark CANCEL_ALL to cancel all matching the key, and use
48 	 * CANCEL_FD to cancel requests matching the specified fd.
49 	 * This should cancel all the pending poll requests on the pipe
50 	 * input.
51 	 */
52 	io_uring_prep_cancel(sqe, 0, IORING_ASYNC_CANCEL_ALL);
53 	sqe->cancel_flags |= IORING_ASYNC_CANCEL_FD;
54 	sqe->fd = fd[0];
55 	sqe->user_data = 100;
56 
57 	ret = io_uring_submit(ring);
58 	if (ret < 1) {
59 		fprintf(stderr, "child: sqe submit failed: %d\n", ret);
60 		return 1;
61 	}
62 
63 	for (i = 0; i < 9; i++) {
64 		if (no_cancel_flags)
65 			break;
66 		ret = io_uring_wait_cqe(ring, &cqe);
67 		if (ret) {
68 			fprintf(stderr, "wait=%d\n", ret);
69 			return 1;
70 		}
71 		switch (cqe->user_data) {
72 		case 100:
73 			if (cqe->res == -EINVAL) {
74 				no_cancel_flags = 1;
75 				break;
76 			}
77 			if (cqe->res != 8) {
78 				fprintf(stderr, "canceled %d\n", cqe->res);
79 				return 1;
80 			}
81 			break;
82 		case 1 ... 8:
83 			if (cqe->res != -ECANCELED) {
84 				fprintf(stderr, "poll res %d\n", cqe->res);
85 				return 1;
86 			}
87 			break;
88 		default:
89 			fprintf(stderr, "invalid user_data %lu\n",
90 					(unsigned long) cqe->user_data);
91 			return 1;
92 		}
93 		io_uring_cqe_seen(ring, cqe);
94 	}
95 
96 	return 0;
97 }
98 
test2(struct io_uring * ring,int * fd)99 static int test2(struct io_uring *ring, int *fd)
100 {
101 	struct io_uring_sqe *sqe;
102 	struct io_uring_cqe *cqe;
103 	int ret, i, fd2[2];
104 
105 	if (pipe(fd2) < 0) {
106 		perror("pipe");
107 		return 1;
108 	}
109 
110 	for (i = 0; i < 8; i++) {
111 		sqe = io_uring_get_sqe(ring);
112 		if (!sqe) {
113 			fprintf(stderr, "get sqe failed\n");
114 			goto err;
115 		}
116 
117 		if (!(i & 1))
118 			io_uring_prep_poll_add(sqe, fd[0], POLLIN);
119 		else
120 			io_uring_prep_poll_add(sqe, fd2[0], POLLIN);
121 		sqe->user_data = i & 1;
122 	}
123 
124 	ret = io_uring_submit(ring);
125 	if (ret < 8) {
126 		fprintf(stderr, "sqe submit failed: %d\n", ret);
127 		goto err;
128 	}
129 
130 	sqe = io_uring_get_sqe(ring);
131 	if (!sqe) {
132 		fprintf(stderr, "get sqe failed\n");
133 		goto err;
134 	}
135 
136 	/*
137 	 * Mark CANCEL_ALL to cancel all matching the key, and use
138 	 * CANCEL_FD to cancel requests matching the specified fd.
139 	 * This should cancel all the pending poll requests on the pipe
140 	 * input.
141 	 */
142 	io_uring_prep_cancel(sqe, 0, IORING_ASYNC_CANCEL_ALL);
143 	sqe->cancel_flags |= IORING_ASYNC_CANCEL_FD;
144 	sqe->fd = fd[0];
145 	sqe->user_data = 100;
146 
147 	ret = io_uring_submit(ring);
148 	if (ret < 1) {
149 		fprintf(stderr, "sqe submit failed: %d\n", ret);
150 		goto err;
151 	}
152 
153 	for (i = 0; i < 5; i++) {
154 		ret = io_uring_wait_cqe(ring, &cqe);
155 		if (ret) {
156 			fprintf(stderr, "wait=%d\n", ret);
157 			goto err;
158 		}
159 		switch (cqe->user_data) {
160 		case 100:
161 			if (cqe->res != 4) {
162 				fprintf(stderr, "canceled %d\n", cqe->res);
163 				goto err;
164 			}
165 			break;
166 		case 0:
167 			if (cqe->res != -ECANCELED) {
168 				fprintf(stderr, "poll res %d\n", cqe->res);
169 				goto err;
170 			}
171 			break;
172 		default:
173 			fprintf(stderr, "invalid user_data %lu\n",
174 					(unsigned long) cqe->user_data);
175 			goto err;
176 		}
177 		io_uring_cqe_seen(ring, cqe);
178 	}
179 
180 	usleep(1000);
181 
182 	/*
183 	 * Should not have any pending CQEs now
184 	 */
185 	ret = io_uring_peek_cqe(ring, &cqe);
186 	if (!ret) {
187 		fprintf(stderr, "Unexpected extra cancel cqe\n");
188 		goto err;
189 	}
190 
191 	sqe = io_uring_get_sqe(ring);
192 	if (!sqe) {
193 		fprintf(stderr, "get sqe failed\n");
194 		goto err;
195 	}
196 
197 	/*
198 	 * Mark CANCEL_ALL to cancel all matching the key, and use
199 	 * CANCEL_FD to cancel requests matching the specified fd.
200 	 * This should cancel all the pending poll requests on the pipe
201 	 * input.
202 	 */
203 	io_uring_prep_cancel(sqe, 0, IORING_ASYNC_CANCEL_ALL);
204 	sqe->cancel_flags |= IORING_ASYNC_CANCEL_FD;
205 	sqe->fd = fd2[0];
206 	sqe->user_data = 100;
207 
208 	ret = io_uring_submit(ring);
209 	if (ret < 1) {
210 		fprintf(stderr, "sqe submit failed: %d\n", ret);
211 		goto err;
212 	}
213 
214 	for (i = 0; i < 5; i++) {
215 		ret = io_uring_wait_cqe(ring, &cqe);
216 		if (ret) {
217 			fprintf(stderr, "wait=%d\n", ret);
218 			goto err;
219 		}
220 		switch (cqe->user_data) {
221 		case 100:
222 			if (cqe->res != 4) {
223 				fprintf(stderr, "canceled %d\n", cqe->res);
224 				goto err;
225 			}
226 			break;
227 		case 1:
228 			if (cqe->res != -ECANCELED) {
229 				fprintf(stderr, "poll res %d\n", cqe->res);
230 				goto err;
231 			}
232 			break;
233 		default:
234 			fprintf(stderr, "invalid user_data %lu\n",
235 					(unsigned long) cqe->user_data);
236 			goto err;
237 		}
238 		io_uring_cqe_seen(ring, cqe);
239 	}
240 
241 	close(fd2[0]);
242 	close(fd2[1]);
243 	return 0;
244 err:
245 	close(fd2[0]);
246 	close(fd2[1]);
247 	return 1;
248 }
249 
test3(struct io_uring * ring,int * fd)250 static int test3(struct io_uring *ring, int *fd)
251 {
252 	struct io_uring_sqe *sqe;
253 	struct io_uring_cqe *cqe;
254 	int ret, i, fd2[2];
255 
256 	if (pipe(fd2) < 0) {
257 		perror("pipe");
258 		return 1;
259 	}
260 
261 	for (i = 0; i < 8; i++) {
262 		sqe = io_uring_get_sqe(ring);
263 		if (!sqe) {
264 			fprintf(stderr, "get sqe failed\n");
265 			goto err;
266 		}
267 
268 		if (!(i & 1)) {
269 			io_uring_prep_poll_add(sqe, fd[0], POLLIN);
270 			sqe->flags |= IOSQE_ASYNC;
271 		} else
272 			io_uring_prep_poll_add(sqe, fd2[0], POLLIN);
273 		sqe->user_data = i & 1;
274 	}
275 
276 	ret = io_uring_submit(ring);
277 	if (ret < 8) {
278 		fprintf(stderr, "child: sqe submit failed: %d\n", ret);
279 		goto err;
280 	}
281 
282 	usleep(10000);
283 
284 	sqe = io_uring_get_sqe(ring);
285 	if (!sqe) {
286 		fprintf(stderr, "get sqe failed\n");
287 		goto err;
288 	}
289 
290 	/*
291 	 * Mark CANCEL_ALL to cancel all matching the key, and use
292 	 * CANCEL_FD to cancel requests matching the specified fd.
293 	 * This should cancel all the pending poll requests on the pipe
294 	 * input.
295 	 */
296 	io_uring_prep_cancel(sqe, 0, IORING_ASYNC_CANCEL_ALL);
297 	sqe->cancel_flags |= IORING_ASYNC_CANCEL_ANY;
298 	sqe->fd = 0;
299 	sqe->user_data = 100;
300 
301 	ret = io_uring_submit(ring);
302 	if (ret < 1) {
303 		fprintf(stderr, "child: sqe submit failed: %d\n", ret);
304 		goto err;
305 	}
306 
307 	for (i = 0; i < 9; i++) {
308 		ret = io_uring_wait_cqe(ring, &cqe);
309 		if (ret) {
310 			fprintf(stderr, "wait=%d\n", ret);
311 			goto err;
312 		}
313 		switch (cqe->user_data) {
314 		case 100:
315 			if (cqe->res != 8) {
316 				fprintf(stderr, "canceled %d\n", cqe->res);
317 				goto err;
318 			}
319 			break;
320 		case 0:
321 		case 1:
322 			if (cqe->res != -ECANCELED) {
323 				fprintf(stderr, "poll res %d\n", cqe->res);
324 				goto err;
325 			}
326 			break;
327 		default:
328 			fprintf(stderr, "invalid user_data %lu\n",
329 					(unsigned long) cqe->user_data);
330 			goto err;
331 		}
332 		io_uring_cqe_seen(ring, cqe);
333 	}
334 
335 	close(fd2[0]);
336 	close(fd2[1]);
337 	return 0;
338 err:
339 	close(fd2[0]);
340 	close(fd2[1]);
341 	return 1;
342 }
343 
test4(struct io_uring * ring,int * fd)344 static int test4(struct io_uring *ring, int *fd)
345 {
346 	struct io_uring_sqe *sqe;
347 	struct io_uring_cqe *cqe;
348 	char buffer[32];
349 	int ret, i;
350 
351 	for (i = 0; i < 8; i++) {
352 		sqe = io_uring_get_sqe(ring);
353 		if (!sqe) {
354 			fprintf(stderr, "get sqe failed\n");
355 			goto err;
356 		}
357 
358 		io_uring_prep_read(sqe, fd[0], &buffer, sizeof(buffer), 0);
359 		sqe->flags |= IOSQE_ASYNC;
360 		sqe->user_data = i + 1;
361 	}
362 
363 	ret = io_uring_submit(ring);
364 	if (ret < 8) {
365 		fprintf(stderr, "child: sqe submit failed: %d\n", ret);
366 		goto err;
367 	}
368 
369 	usleep(10000);
370 
371 	sqe = io_uring_get_sqe(ring);
372 	if (!sqe) {
373 		fprintf(stderr, "get sqe failed\n");
374 		goto err;
375 	}
376 
377 	/*
378 	 * Mark CANCEL_ALL to cancel all matching the key, and use
379 	 * CANCEL_FD to cancel requests matching the specified fd.
380 	 * This should cancel all the pending poll requests on the pipe
381 	 * input.
382 	 */
383 	io_uring_prep_cancel(sqe, 0, IORING_ASYNC_CANCEL_ALL);
384 	sqe->cancel_flags |= IORING_ASYNC_CANCEL_ANY;
385 	sqe->fd = 0;
386 	sqe->user_data = 100;
387 
388 	ret = io_uring_submit(ring);
389 	if (ret < 1) {
390 		fprintf(stderr, "child: sqe submit failed: %d\n", ret);
391 		goto err;
392 	}
393 
394 	for (i = 0; i < 9; i++) {
395 		ret = io_uring_wait_cqe(ring, &cqe);
396 		if (ret) {
397 			fprintf(stderr, "wait=%d\n", ret);
398 			goto err;
399 		}
400 		switch (cqe->user_data) {
401 		case 100:
402 			if (cqe->res != 8) {
403 				fprintf(stderr, "canceled %d\n", cqe->res);
404 				goto err;
405 			}
406 			break;
407 		case 1 ... 8:
408 			if (cqe->res != -ECANCELED) {
409 				fprintf(stderr, "poll res %d\n", cqe->res);
410 				goto err;
411 			}
412 			break;
413 		default:
414 			fprintf(stderr, "invalid user_data %lu\n",
415 					(unsigned long) cqe->user_data);
416 			goto err;
417 		}
418 		io_uring_cqe_seen(ring, cqe);
419 	}
420 
421 	return 0;
422 err:
423 	return 1;
424 }
425 
main(int argc,char * argv[])426 int main(int argc, char *argv[])
427 {
428 	struct io_uring ring;
429 	int ret, fd[2];
430 
431 	if (argc > 1)
432 		return 0;
433 
434 	if (pipe(fd) < 0) {
435 		perror("pipe");
436 		return 1;
437 	}
438 
439 	ret = io_uring_queue_init(8, &ring, 0);
440 	if (ret) {
441 		fprintf(stderr, "ring setup failed: %d\n", ret);
442 		return 1;
443 	}
444 
445 	ret = test1(&ring, fd);
446 	if (ret) {
447 		fprintf(stderr, "test1 failed\n");
448 		return ret;
449 	}
450 	if (no_cancel_flags)
451 		return 0;
452 
453 	ret = test2(&ring, fd);
454 	if (ret) {
455 		fprintf(stderr, "test2 failed\n");
456 		return ret;
457 	}
458 
459 	ret = test3(&ring, fd);
460 	if (ret) {
461 		fprintf(stderr, "test3 failed\n");
462 		return ret;
463 	}
464 
465 	ret = test4(&ring, fd);
466 	if (ret) {
467 		fprintf(stderr, "test4 failed\n");
468 		return ret;
469 	}
470 
471 	return 0;
472 }
473