• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: MIT */
2 /*
3  * Description: run various timeout tests
4  *
5  */
6 #include <errno.h>
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <fcntl.h>
12 #include <sys/time.h>
13 
14 #include "liburing.h"
15 #include "../src/syscall.h"
16 
17 #define TIMEOUT_MSEC	200
18 static int not_supported;
19 static int no_modify;
20 
msec_to_ts(struct __kernel_timespec * ts,unsigned int msec)21 static void msec_to_ts(struct __kernel_timespec *ts, unsigned int msec)
22 {
23 	ts->tv_sec = msec / 1000;
24 	ts->tv_nsec = (msec % 1000) * 1000000;
25 }
26 
mtime_since(const struct timeval * s,const struct timeval * e)27 static unsigned long long mtime_since(const struct timeval *s,
28 				      const struct timeval *e)
29 {
30 	long long sec, usec;
31 
32 	sec = e->tv_sec - s->tv_sec;
33 	usec = (e->tv_usec - s->tv_usec);
34 	if (sec > 0 && usec < 0) {
35 		sec--;
36 		usec += 1000000;
37 	}
38 
39 	sec *= 1000;
40 	usec /= 1000;
41 	return sec + usec;
42 }
43 
mtime_since_now(struct timeval * tv)44 static unsigned long long mtime_since_now(struct timeval *tv)
45 {
46 	struct timeval end;
47 
48 	gettimeofday(&end, NULL);
49 	return mtime_since(tv, &end);
50 }
51 
52 /*
53  * Test that we return to userspace if a timeout triggers, even if we
54  * don't satisfy the number of events asked for.
55  */
test_single_timeout_many(struct io_uring * ring)56 static int test_single_timeout_many(struct io_uring *ring)
57 {
58 	struct io_uring_cqe *cqe;
59 	struct io_uring_sqe *sqe;
60 	unsigned long long exp;
61 	struct __kernel_timespec ts;
62 	struct timeval tv;
63 	int ret;
64 
65 	sqe = io_uring_get_sqe(ring);
66 	if (!sqe) {
67 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
68 		goto err;
69 	}
70 
71 	msec_to_ts(&ts, TIMEOUT_MSEC);
72 	io_uring_prep_timeout(sqe, &ts, 0, 0);
73 
74 	ret = io_uring_submit(ring);
75 	if (ret <= 0) {
76 		fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
77 		goto err;
78 	}
79 
80 	gettimeofday(&tv, NULL);
81 	ret = __sys_io_uring_enter(ring->ring_fd, 0, 4, IORING_ENTER_GETEVENTS,
82 					NULL);
83 	if (ret < 0) {
84 		fprintf(stderr, "%s: io_uring_enter %d\n", __FUNCTION__, ret);
85 		goto err;
86 	}
87 
88 	ret = io_uring_wait_cqe(ring, &cqe);
89 	if (ret < 0) {
90 		fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
91 		goto err;
92 	}
93 	ret = cqe->res;
94 	io_uring_cqe_seen(ring, cqe);
95 	if (ret == -EINVAL) {
96 		fprintf(stdout, "Timeout not supported, ignored\n");
97 		not_supported = 1;
98 		return 0;
99 	} else if (ret != -ETIME) {
100 		fprintf(stderr, "Timeout: %s\n", strerror(-ret));
101 		goto err;
102 	}
103 
104 	exp = mtime_since_now(&tv);
105 	if (exp >= TIMEOUT_MSEC / 2 && exp <= (TIMEOUT_MSEC * 3) / 2)
106 		return 0;
107 	fprintf(stderr, "%s: Timeout seems wonky (got %llu)\n", __FUNCTION__, exp);
108 err:
109 	return 1;
110 }
111 
112 /*
113  * Test numbered trigger of timeout
114  */
test_single_timeout_nr(struct io_uring * ring,int nr)115 static int test_single_timeout_nr(struct io_uring *ring, int nr)
116 {
117 	struct io_uring_cqe *cqe;
118 	struct io_uring_sqe *sqe;
119 	struct __kernel_timespec ts;
120 	int i, ret;
121 
122 	sqe = io_uring_get_sqe(ring);
123 	if (!sqe) {
124 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
125 		goto err;
126 	}
127 
128 	msec_to_ts(&ts, TIMEOUT_MSEC);
129 	io_uring_prep_timeout(sqe, &ts, nr, 0);
130 
131 	sqe = io_uring_get_sqe(ring);
132 	io_uring_prep_nop(sqe);
133 	io_uring_sqe_set_data(sqe, (void *) 1);
134 	sqe = io_uring_get_sqe(ring);
135 	io_uring_prep_nop(sqe);
136 	io_uring_sqe_set_data(sqe, (void *) 1);
137 
138 	ret = io_uring_submit_and_wait(ring, 3);
139 	if (ret <= 0) {
140 		fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
141 		goto err;
142 	}
143 
144 	i = 0;
145 	while (i < 3) {
146 		ret = io_uring_wait_cqe(ring, &cqe);
147 		if (ret < 0) {
148 			fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
149 			goto err;
150 		}
151 
152 		ret = cqe->res;
153 
154 		/*
155 		 * NOP commands have user_data as 1. Check that we get the
156 		 * at least 'nr' NOPs first, then the successfully removed timout.
157 		 */
158 		if (io_uring_cqe_get_data(cqe) == NULL) {
159 			if (i < nr) {
160 				fprintf(stderr, "%s: timeout received too early\n", __FUNCTION__);
161 				goto err;
162 			}
163 			if (ret) {
164 				fprintf(stderr, "%s: timeout triggered by passage of"
165 					" time, not by events completed\n", __FUNCTION__);
166 				goto err;
167 			}
168 		}
169 
170 		io_uring_cqe_seen(ring, cqe);
171 		if (ret) {
172 			fprintf(stderr, "res: %d\n", ret);
173 			goto err;
174 		}
175 		i++;
176 	};
177 
178 	return 0;
179 err:
180 	return 1;
181 }
182 
test_single_timeout_wait(struct io_uring * ring)183 static int test_single_timeout_wait(struct io_uring *ring)
184 {
185 	struct io_uring_cqe *cqe;
186 	struct io_uring_sqe *sqe;
187 	struct __kernel_timespec ts;
188 	int i, ret;
189 
190 	sqe = io_uring_get_sqe(ring);
191 	io_uring_prep_nop(sqe);
192 	io_uring_sqe_set_data(sqe, (void *) 1);
193 
194 	sqe = io_uring_get_sqe(ring);
195 	io_uring_prep_nop(sqe);
196 	io_uring_sqe_set_data(sqe, (void *) 1);
197 
198 	msec_to_ts(&ts, 1000);
199 
200 	i = 0;
201 	do {
202 		ret = io_uring_wait_cqes(ring, &cqe, 2, &ts, NULL);
203 		if (ret == -ETIME)
204 			break;
205 		if (ret < 0) {
206 			fprintf(stderr, "%s: wait timeout failed: %d\n", __FUNCTION__, ret);
207 			goto err;
208 		}
209 
210 		ret = cqe->res;
211 		io_uring_cqe_seen(ring, cqe);
212 		if (ret < 0) {
213 			fprintf(stderr, "res: %d\n", ret);
214 			goto err;
215 		}
216 		i++;
217 	} while (1);
218 
219 	if (i != 2) {
220 		fprintf(stderr, "got %d completions\n", i);
221 		goto err;
222 	}
223 	return 0;
224 err:
225 	return 1;
226 }
227 
228 /*
229  * Test single timeout waking us up
230  */
test_single_timeout(struct io_uring * ring)231 static int test_single_timeout(struct io_uring *ring)
232 {
233 	struct io_uring_cqe *cqe;
234 	struct io_uring_sqe *sqe;
235 	unsigned long long exp;
236 	struct __kernel_timespec ts;
237 	struct timeval tv;
238 	int ret;
239 
240 	sqe = io_uring_get_sqe(ring);
241 	if (!sqe) {
242 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
243 		goto err;
244 	}
245 
246 	msec_to_ts(&ts, TIMEOUT_MSEC);
247 	io_uring_prep_timeout(sqe, &ts, 0, 0);
248 
249 	ret = io_uring_submit(ring);
250 	if (ret <= 0) {
251 		fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
252 		goto err;
253 	}
254 
255 	gettimeofday(&tv, NULL);
256 	ret = io_uring_wait_cqe(ring, &cqe);
257 	if (ret < 0) {
258 		fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
259 		goto err;
260 	}
261 	ret = cqe->res;
262 	io_uring_cqe_seen(ring, cqe);
263 	if (ret == -EINVAL) {
264 		fprintf(stdout, "%s: Timeout not supported, ignored\n", __FUNCTION__);
265 		not_supported = 1;
266 		return 0;
267 	} else if (ret != -ETIME) {
268 		fprintf(stderr, "%s: Timeout: %s\n", __FUNCTION__, strerror(-ret));
269 		goto err;
270 	}
271 
272 	exp = mtime_since_now(&tv);
273 	if (exp >= TIMEOUT_MSEC / 2 && exp <= (TIMEOUT_MSEC * 3) / 2)
274 		return 0;
275 	fprintf(stderr, "%s: Timeout seems wonky (got %llu)\n", __FUNCTION__, exp);
276 err:
277 	return 1;
278 }
279 
test_single_timeout_remove_notfound(struct io_uring * ring)280 static int test_single_timeout_remove_notfound(struct io_uring *ring)
281 {
282 	struct io_uring_cqe *cqe;
283 	struct io_uring_sqe *sqe;
284 	struct __kernel_timespec ts;
285 	int ret, i;
286 
287 	if (no_modify)
288 		return 0;
289 
290 	sqe = io_uring_get_sqe(ring);
291 	if (!sqe) {
292 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
293 		goto err;
294 	}
295 
296 	msec_to_ts(&ts, TIMEOUT_MSEC);
297 	io_uring_prep_timeout(sqe, &ts, 2, 0);
298 	sqe->user_data = 1;
299 
300 	ret = io_uring_submit(ring);
301 	if (ret <= 0) {
302 		fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
303 		goto err;
304 	}
305 
306 	sqe = io_uring_get_sqe(ring);
307 	if (!sqe) {
308 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
309 		goto err;
310 	}
311 
312 	io_uring_prep_timeout_remove(sqe, 2, 0);
313 	sqe->user_data = 2;
314 
315 	ret = io_uring_submit(ring);
316 	if (ret <= 0) {
317 		fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
318 		goto err;
319 	}
320 
321 	/*
322 	 * We should get two completions. One is our modify request, which should
323 	 * complete with -ENOENT. The other is the timeout that will trigger after
324 	 * TIMEOUT_MSEC.
325 	 */
326 	for (i = 0; i < 2; i++) {
327 		ret = io_uring_wait_cqe(ring, &cqe);
328 		if (ret < 0) {
329 			fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
330 			goto err;
331 		}
332 		if (cqe->user_data == 2) {
333 			if (cqe->res != -ENOENT) {
334 				fprintf(stderr, "%s: modify ret %d, wanted ENOENT\n", __FUNCTION__, cqe->res);
335 				break;
336 			}
337 		} else if (cqe->user_data == 1) {
338 			if (cqe->res != -ETIME) {
339 				fprintf(stderr, "%s: timeout ret %d, wanted -ETIME\n", __FUNCTION__, cqe->res);
340 				break;
341 			}
342 		}
343 		io_uring_cqe_seen(ring, cqe);
344 	}
345 	return 0;
346 err:
347 	return 1;
348 }
349 
test_single_timeout_remove(struct io_uring * ring)350 static int test_single_timeout_remove(struct io_uring *ring)
351 {
352 	struct io_uring_cqe *cqe;
353 	struct io_uring_sqe *sqe;
354 	struct __kernel_timespec ts;
355 	int ret, i;
356 
357 	sqe = io_uring_get_sqe(ring);
358 	if (!sqe) {
359 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
360 		goto err;
361 	}
362 
363 	msec_to_ts(&ts, TIMEOUT_MSEC);
364 	io_uring_prep_timeout(sqe, &ts, 0, 0);
365 	sqe->user_data = 1;
366 
367 	ret = io_uring_submit(ring);
368 	if (ret <= 0) {
369 		fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
370 		goto err;
371 	}
372 
373 	sqe = io_uring_get_sqe(ring);
374 	if (!sqe) {
375 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
376 		goto err;
377 	}
378 
379 	io_uring_prep_timeout_remove(sqe, 1, 0);
380 	sqe->user_data = 2;
381 
382 	ret = io_uring_submit(ring);
383 	if (ret <= 0) {
384 		fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
385 		goto err;
386 	}
387 
388 	/*
389 	 * We should have two completions ready. One is for the original timeout
390 	 * request, user_data == 1, that should have a ret of -ECANCELED. The other
391 	 * is for our modify request, user_data == 2, that should have a ret of 0.
392 	 */
393 	for (i = 0; i < 2; i++) {
394 		ret = io_uring_wait_cqe(ring, &cqe);
395 		if (ret < 0) {
396 			fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
397 			goto err;
398 		}
399 		if (no_modify)
400 			goto seen;
401 		if (cqe->res == -EINVAL && cqe->user_data == 2) {
402 			fprintf(stdout, "Timeout modify not supported, ignoring\n");
403 			no_modify = 1;
404 			goto seen;
405 		}
406 		if (cqe->user_data == 1) {
407 			if (cqe->res != -ECANCELED) {
408 				fprintf(stderr, "%s: timeout ret %d, wanted canceled\n", __FUNCTION__, cqe->res);
409 				break;
410 			}
411 		} else if (cqe->user_data == 2) {
412 			if (cqe->res) {
413 				fprintf(stderr, "%s: modify ret %d, wanted 0\n", __FUNCTION__, cqe->res);
414 				break;
415 			}
416 		}
417 seen:
418 		io_uring_cqe_seen(ring, cqe);
419 	}
420 	return 0;
421 err:
422 	return 1;
423 }
424 
425 /*
426  * Test single absolute timeout waking us up
427  */
test_single_timeout_abs(struct io_uring * ring)428 static int test_single_timeout_abs(struct io_uring *ring)
429 {
430 	struct io_uring_cqe *cqe;
431 	struct io_uring_sqe *sqe;
432 	unsigned long long exp;
433 	struct __kernel_timespec ts;
434 	struct timespec abs_ts;
435 	struct timeval tv;
436 	int ret;
437 
438 	sqe = io_uring_get_sqe(ring);
439 	if (!sqe) {
440 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
441 		goto err;
442 	}
443 
444 	clock_gettime(CLOCK_MONOTONIC, &abs_ts);
445 	ts.tv_sec = abs_ts.tv_sec + 1;
446 	ts.tv_nsec = abs_ts.tv_nsec;
447 	io_uring_prep_timeout(sqe, &ts, 0, IORING_TIMEOUT_ABS);
448 
449 	ret = io_uring_submit(ring);
450 	if (ret <= 0) {
451 		fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
452 		goto err;
453 	}
454 
455 	gettimeofday(&tv, NULL);
456 	ret = io_uring_wait_cqe(ring, &cqe);
457 	if (ret < 0) {
458 		fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
459 		goto err;
460 	}
461 	ret = cqe->res;
462 	io_uring_cqe_seen(ring, cqe);
463 	if (ret == -EINVAL) {
464 		fprintf(stdout, "Absolute timeouts not supported, ignored\n");
465 		return 0;
466 	} else if (ret != -ETIME) {
467 		fprintf(stderr, "Timeout: %s\n", strerror(-ret));
468 		goto err;
469 	}
470 
471 	exp = mtime_since_now(&tv);
472 	if (exp >= 1000 / 2 && exp <= (1000 * 3) / 2)
473 		return 0;
474 	fprintf(stderr, "%s: Timeout seems wonky (got %llu)\n", __FUNCTION__, exp);
475 err:
476 	return 1;
477 }
478 
479 /*
480  * Test that timeout is canceled on exit
481  */
test_single_timeout_exit(struct io_uring * ring)482 static int test_single_timeout_exit(struct io_uring *ring)
483 {
484 	struct io_uring_sqe *sqe;
485 	struct __kernel_timespec ts;
486 	int ret;
487 
488 	sqe = io_uring_get_sqe(ring);
489 	if (!sqe) {
490 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
491 		goto err;
492 	}
493 
494 	msec_to_ts(&ts, 30000);
495 	io_uring_prep_timeout(sqe, &ts, 0, 0);
496 
497 	ret = io_uring_submit(ring);
498 	if (ret <= 0) {
499 		fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
500 		goto err;
501 	}
502 
503 	io_uring_queue_exit(ring);
504 	return 0;
505 err:
506 	io_uring_queue_exit(ring);
507 	return 1;
508 }
509 
510 /*
511  * Test multi timeouts waking us up
512  */
test_multi_timeout(struct io_uring * ring)513 static int test_multi_timeout(struct io_uring *ring)
514 {
515 	struct io_uring_sqe *sqe;
516 	struct io_uring_cqe *cqe;
517 	struct __kernel_timespec ts[2];
518 	unsigned int timeout[2];
519 	unsigned long long exp;
520 	struct timeval tv;
521 	int ret, i;
522 
523 	/* req_1: timeout req, count = 1, time = (TIMEOUT_MSEC * 2) */
524 	timeout[0] = TIMEOUT_MSEC * 2;
525 	msec_to_ts(&ts[0], timeout[0]);
526 	sqe = io_uring_get_sqe(ring);
527 	if (!sqe) {
528 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
529 		goto err;
530 	}
531 	io_uring_prep_timeout(sqe, &ts[0], 1, 0);
532 	sqe->user_data = 1;
533 
534 	/* req_2: timeout req, count = 1, time = TIMEOUT_MSEC */
535 	timeout[1] = TIMEOUT_MSEC;
536 	msec_to_ts(&ts[1], timeout[1]);
537 	sqe = io_uring_get_sqe(ring);
538 	if (!sqe) {
539 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
540 		goto err;
541 	}
542 	io_uring_prep_timeout(sqe, &ts[1], 1, 0);
543 	sqe->user_data = 2;
544 
545 	ret = io_uring_submit(ring);
546 	if (ret <= 0) {
547 		fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
548 		goto err;
549 	}
550 
551 	gettimeofday(&tv, NULL);
552 	for (i = 0; i < 2; i++) {
553 		unsigned int time;
554 		__u64 user_data;
555 
556 		ret = io_uring_wait_cqe(ring, &cqe);
557 		if (ret < 0) {
558 			fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
559 			goto err;
560 		}
561 
562 		/*
563 		 * Both of these two reqs should timeout, but req_2 should
564 		 * return before req_1.
565 		 */
566 		switch (i) {
567 		case 0:
568 			user_data = 2;
569 			time = timeout[1];
570 			break;
571 		case 1:
572 			user_data = 1;
573 			time = timeout[0];
574 			break;
575 		}
576 
577 		if (cqe->user_data != user_data) {
578 			fprintf(stderr, "%s: unexpected timeout req %d sequece\n",
579 				__FUNCTION__, i+1);
580 			goto err;
581 		}
582 		if (cqe->res != -ETIME) {
583 			fprintf(stderr, "%s: Req %d timeout: %s\n",
584 				__FUNCTION__, i+1, strerror(cqe->res));
585 			goto err;
586 		}
587 		exp = mtime_since_now(&tv);
588 		if (exp < time / 2 || exp > (time * 3) / 2) {
589 			fprintf(stderr, "%s: Req %d timeout seems wonky (got %llu)\n",
590 				__FUNCTION__, i+1, exp);
591 			goto err;
592 		}
593 		io_uring_cqe_seen(ring, cqe);
594 	}
595 
596 	return 0;
597 err:
598 	return 1;
599 }
600 
601 /*
602  * Test multi timeout req with different count
603  */
test_multi_timeout_nr(struct io_uring * ring)604 static int test_multi_timeout_nr(struct io_uring *ring)
605 {
606 	struct io_uring_sqe *sqe;
607 	struct io_uring_cqe *cqe;
608 	struct __kernel_timespec ts;
609 	int ret, i;
610 
611 	msec_to_ts(&ts, TIMEOUT_MSEC);
612 
613 	/* req_1: timeout req, count = 2 */
614 	sqe = io_uring_get_sqe(ring);
615 	if (!sqe) {
616 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
617 		goto err;
618 	}
619 	io_uring_prep_timeout(sqe, &ts, 2, 0);
620 	sqe->user_data = 1;
621 
622 	/* req_2: timeout req, count = 1 */
623 	sqe = io_uring_get_sqe(ring);
624 	if (!sqe) {
625 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
626 		goto err;
627 	}
628 	io_uring_prep_timeout(sqe, &ts, 1, 0);
629 	sqe->user_data = 2;
630 
631 	/* req_3: nop req */
632 	sqe = io_uring_get_sqe(ring);
633 	if (!sqe) {
634 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
635 		goto err;
636 	}
637 	io_uring_prep_nop(sqe);
638 	io_uring_sqe_set_data(sqe, (void *) 1);
639 
640 	ret = io_uring_submit(ring);
641 	if (ret <= 0) {
642 		fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
643 		goto err;
644 	}
645 
646 	/*
647 	 * req_2 (count=1) should return without error and req_1 (count=2)
648 	 * should timeout.
649 	 */
650 	for (i = 0; i < 3; i++) {
651 		ret = io_uring_wait_cqe(ring, &cqe);
652 		if (ret < 0) {
653 			fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
654 			goto err;
655 		}
656 
657 		switch (i) {
658 		case 0:
659 			/* Should be nop req */
660 			if (io_uring_cqe_get_data(cqe) != (void *) 1) {
661 				fprintf(stderr, "%s: nop not seen as 1 or 2\n", __FUNCTION__);
662 				goto err;
663 			}
664 			break;
665 		case 1:
666 			/* Should be timeout req_2 */
667 			if (cqe->user_data != 2) {
668 				fprintf(stderr, "%s: unexpected timeout req %d sequece\n",
669 					__FUNCTION__, i+1);
670 				goto err;
671 			}
672 			if (cqe->res < 0) {
673 				fprintf(stderr, "%s: Req %d res %d\n",
674 					__FUNCTION__, i+1, cqe->res);
675 				goto err;
676 			}
677 			break;
678 		case 2:
679 			/* Should be timeout req_1 */
680 			if (cqe->user_data != 1) {
681 				fprintf(stderr, "%s: unexpected timeout req %d sequece\n",
682 					__FUNCTION__, i+1);
683 				goto err;
684 			}
685 			if (cqe->res != -ETIME) {
686 				fprintf(stderr, "%s: Req %d timeout: %s\n",
687 					__FUNCTION__, i+1, strerror(cqe->res));
688 				goto err;
689 			}
690 			break;
691 		}
692 		io_uring_cqe_seen(ring, cqe);
693 	}
694 
695 	return 0;
696 err:
697 	return 1;
698 }
699 
700 /*
701  * Test timeout <link> timeout <drain> timeout
702  */
test_timeout_flags1(struct io_uring * ring)703 static int test_timeout_flags1(struct io_uring *ring)
704 {
705 	struct io_uring_sqe *sqe;
706 	struct io_uring_cqe *cqe;
707 	struct __kernel_timespec ts;
708 	int ret, i;
709 
710 	msec_to_ts(&ts, TIMEOUT_MSEC);
711 
712 	sqe = io_uring_get_sqe(ring);
713 	if (!sqe) {
714 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
715 		goto err;
716 	}
717 	io_uring_prep_timeout(sqe, &ts, 0, 0);
718 	sqe->user_data = 1;
719 	sqe->flags |= IOSQE_IO_LINK;
720 
721 	sqe = io_uring_get_sqe(ring);
722 	if (!sqe) {
723 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
724 		goto err;
725 	}
726 	io_uring_prep_timeout(sqe, &ts, 0, 0);
727 	sqe->user_data = 2;
728 	sqe->flags |= IOSQE_IO_DRAIN;
729 
730 	sqe = io_uring_get_sqe(ring);
731 	if (!sqe) {
732 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
733 		goto err;
734 	}
735 	io_uring_prep_timeout(sqe, &ts, 0, 0);
736 	sqe->user_data = 3;
737 
738 	ret = io_uring_submit(ring);
739 	if (ret <= 0) {
740 		fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
741 		goto err;
742 	}
743 
744 	for (i = 0; i < 3; i++) {
745 		ret = io_uring_wait_cqe(ring, &cqe);
746 		if (ret < 0) {
747 			fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
748 			goto err;
749 		}
750 
751 		if (cqe->res == -EINVAL) {
752 			if (!i)
753 				fprintf(stdout, "%s: timeout flags not supported\n",
754 						__FUNCTION__);
755 			io_uring_cqe_seen(ring, cqe);
756 			continue;
757 		}
758 
759 		switch (cqe->user_data) {
760 		case 1:
761 			if (cqe->res != -ETIME) {
762 				fprintf(stderr, "%s: got %d, wanted %d\n",
763 						__FUNCTION__, cqe->res, -ETIME);
764 				goto err;
765 			}
766 			break;
767 		case 2:
768 			if (cqe->res != -ECANCELED) {
769 				fprintf(stderr, "%s: got %d, wanted %d\n",
770 						__FUNCTION__, cqe->res,
771 						-ECANCELED);
772 				goto err;
773 			}
774 			break;
775 		case 3:
776 			if (cqe->res != -ETIME) {
777 				fprintf(stderr, "%s: got %d, wanted %d\n",
778 						__FUNCTION__, cqe->res, -ETIME);
779 				goto err;
780 			}
781 			break;
782 		}
783 		io_uring_cqe_seen(ring, cqe);
784 	}
785 
786 	return 0;
787 err:
788 	return 1;
789 }
790 
791 /*
792  * Test timeout <link> timeout <link> timeout
793  */
test_timeout_flags2(struct io_uring * ring)794 static int test_timeout_flags2(struct io_uring *ring)
795 {
796 	struct io_uring_sqe *sqe;
797 	struct io_uring_cqe *cqe;
798 	struct __kernel_timespec ts;
799 	int ret, i;
800 
801 	msec_to_ts(&ts, TIMEOUT_MSEC);
802 
803 	sqe = io_uring_get_sqe(ring);
804 	if (!sqe) {
805 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
806 		goto err;
807 	}
808 	io_uring_prep_timeout(sqe, &ts, 0, 0);
809 	sqe->user_data = 1;
810 	sqe->flags |= IOSQE_IO_LINK;
811 
812 	sqe = io_uring_get_sqe(ring);
813 	if (!sqe) {
814 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
815 		goto err;
816 	}
817 	io_uring_prep_timeout(sqe, &ts, 0, 0);
818 	sqe->user_data = 2;
819 	sqe->flags |= IOSQE_IO_LINK;
820 
821 	sqe = io_uring_get_sqe(ring);
822 	if (!sqe) {
823 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
824 		goto err;
825 	}
826 	io_uring_prep_timeout(sqe, &ts, 0, 0);
827 	sqe->user_data = 3;
828 
829 	ret = io_uring_submit(ring);
830 	if (ret <= 0) {
831 		fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
832 		goto err;
833 	}
834 
835 	for (i = 0; i < 3; i++) {
836 		ret = io_uring_wait_cqe(ring, &cqe);
837 		if (ret < 0) {
838 			fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
839 			goto err;
840 		}
841 
842 		if (cqe->res == -EINVAL) {
843 			if (!i)
844 				fprintf(stdout, "%s: timeout flags not supported\n",
845 						__FUNCTION__);
846 			io_uring_cqe_seen(ring, cqe);
847 			continue;
848 		}
849 
850 		switch (cqe->user_data) {
851 		case 1:
852 			if (cqe->res != -ETIME) {
853 				fprintf(stderr, "%s: got %d, wanted %d\n",
854 						__FUNCTION__, cqe->res, -ETIME);
855 				goto err;
856 			}
857 			break;
858 		case 2:
859 		case 3:
860 			if (cqe->res != -ECANCELED) {
861 				fprintf(stderr, "%s: got %d, wanted %d\n",
862 						__FUNCTION__, cqe->res,
863 						-ECANCELED);
864 				goto err;
865 			}
866 			break;
867 		}
868 		io_uring_cqe_seen(ring, cqe);
869 	}
870 
871 	return 0;
872 err:
873 	return 1;
874 }
875 
876 /*
877  * Test timeout <drain> timeout <link> timeout
878  */
test_timeout_flags3(struct io_uring * ring)879 static int test_timeout_flags3(struct io_uring *ring)
880 {
881 	struct io_uring_sqe *sqe;
882 	struct io_uring_cqe *cqe;
883 	struct __kernel_timespec ts;
884 	int ret, i;
885 
886 	msec_to_ts(&ts, TIMEOUT_MSEC);
887 
888 	sqe = io_uring_get_sqe(ring);
889 	if (!sqe) {
890 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
891 		goto err;
892 	}
893 	io_uring_prep_timeout(sqe, &ts, 0, 0);
894 	sqe->user_data = 1;
895 	sqe->flags |= IOSQE_IO_DRAIN;
896 
897 	sqe = io_uring_get_sqe(ring);
898 	if (!sqe) {
899 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
900 		goto err;
901 	}
902 	io_uring_prep_timeout(sqe, &ts, 0, 0);
903 	sqe->user_data = 2;
904 	sqe->flags |= IOSQE_IO_LINK;
905 
906 	sqe = io_uring_get_sqe(ring);
907 	if (!sqe) {
908 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
909 		goto err;
910 	}
911 	io_uring_prep_timeout(sqe, &ts, 0, 0);
912 	sqe->user_data = 3;
913 
914 	ret = io_uring_submit(ring);
915 	if (ret <= 0) {
916 		fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
917 		goto err;
918 	}
919 
920 	for (i = 0; i < 3; i++) {
921 		ret = io_uring_wait_cqe(ring, &cqe);
922 		if (ret < 0) {
923 			fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
924 			goto err;
925 		}
926 
927 		if (cqe->res == -EINVAL) {
928 			if (!i)
929 				fprintf(stdout, "%s: timeout flags not supported\n",
930 						__FUNCTION__);
931 			io_uring_cqe_seen(ring, cqe);
932 			continue;
933 		}
934 
935 		switch (cqe->user_data) {
936 		case 1:
937 		case 2:
938 			if (cqe->res != -ETIME) {
939 				fprintf(stderr, "%s: got %d, wanted %d\n",
940 						__FUNCTION__, cqe->res, -ETIME);
941 				goto err;
942 			}
943 			break;
944 		case 3:
945 			if (cqe->res != -ECANCELED) {
946 				fprintf(stderr, "%s: got %d, wanted %d\n",
947 						__FUNCTION__, cqe->res,
948 						-ECANCELED);
949 				goto err;
950 			}
951 			break;
952 		}
953 		io_uring_cqe_seen(ring, cqe);
954 	}
955 
956 	return 0;
957 err:
958 	return 1;
959 }
960 
test_update_timeout(struct io_uring * ring,unsigned long ms,bool abs,bool async,bool linked)961 static int test_update_timeout(struct io_uring *ring, unsigned long ms,
962 				bool abs, bool async, bool linked)
963 {
964 	struct io_uring_sqe *sqe;
965 	struct io_uring_cqe *cqe;
966 	struct __kernel_timespec ts, ts_upd;
967 	unsigned long long exp_ms, base_ms = 10000;
968 	struct timeval tv;
969 	int ret, i, nr = 2;
970 	__u32 mode = abs ? IORING_TIMEOUT_ABS : 0;
971 
972 	msec_to_ts(&ts_upd, ms);
973 	gettimeofday(&tv, NULL);
974 
975 	sqe = io_uring_get_sqe(ring);
976 	if (!sqe) {
977 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
978 		goto err;
979 	}
980 	msec_to_ts(&ts, base_ms);
981 	io_uring_prep_timeout(sqe, &ts, 0, 0);
982 	sqe->user_data = 1;
983 
984 	if (linked) {
985 		sqe = io_uring_get_sqe(ring);
986 		if (!sqe) {
987 			fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
988 			goto err;
989 		}
990 		io_uring_prep_nop(sqe);
991 		sqe->user_data = 3;
992 		sqe->flags = IOSQE_IO_LINK;
993 		if (async)
994 			sqe->flags |= IOSQE_ASYNC;
995 		nr++;
996 	}
997 
998 	sqe = io_uring_get_sqe(ring);
999 	if (!sqe) {
1000 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
1001 		goto err;
1002 	}
1003 	io_uring_prep_timeout_update(sqe, &ts_upd, 1, mode);
1004 	sqe->user_data = 2;
1005 	if (async)
1006 		sqe->flags |= IOSQE_ASYNC;
1007 
1008 	ret = io_uring_submit(ring);
1009 	if (ret != nr) {
1010 		fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
1011 		goto err;
1012 	}
1013 
1014 	for (i = 0; i < nr; i++) {
1015 		ret = io_uring_wait_cqe(ring, &cqe);
1016 		if (ret < 0) {
1017 			fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
1018 			goto err;
1019 		}
1020 
1021 		switch (cqe->user_data) {
1022 		case 1:
1023 			if (cqe->res != -ETIME) {
1024 				fprintf(stderr, "%s: got %d, wanted %d\n",
1025 						__FUNCTION__, cqe->res, -ETIME);
1026 				goto err;
1027 			}
1028 			break;
1029 		case 2:
1030 			if (cqe->res != 0) {
1031 				fprintf(stderr, "%s: got %d, wanted %d\n",
1032 						__FUNCTION__, cqe->res,
1033 						0);
1034 				goto err;
1035 			}
1036 			break;
1037 		case 3:
1038 			if (cqe->res != 0) {
1039 				fprintf(stderr, "nop failed\n");
1040 				goto err;
1041 			}
1042 			break;
1043 		default:
1044 			goto err;
1045 		}
1046 		io_uring_cqe_seen(ring, cqe);
1047 	}
1048 
1049 	exp_ms = mtime_since_now(&tv);
1050 	if (exp_ms >= base_ms / 2) {
1051 		fprintf(stderr, "too long, timeout wasn't updated\n");
1052 		goto err;
1053 	}
1054 	if (ms >= 1000 && !abs && exp_ms < ms / 2) {
1055 		fprintf(stderr, "fired too early, potentially updated to 0 ms"
1056 					"instead of %lu\n", ms);
1057 		goto err;
1058 	}
1059 	return 0;
1060 err:
1061 	return 1;
1062 }
1063 
test_update_nonexistent_timeout(struct io_uring * ring)1064 static int test_update_nonexistent_timeout(struct io_uring *ring)
1065 {
1066 	struct io_uring_sqe *sqe;
1067 	struct io_uring_cqe *cqe;
1068 	struct __kernel_timespec ts;
1069 	int ret;
1070 
1071 	sqe = io_uring_get_sqe(ring);
1072 	if (!sqe) {
1073 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
1074 		goto err;
1075 	}
1076 	msec_to_ts(&ts, 0);
1077 	io_uring_prep_timeout_update(sqe, &ts, 42, 0);
1078 
1079 	ret = io_uring_submit(ring);
1080 	if (ret != 1) {
1081 		fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
1082 		goto err;
1083 	}
1084 
1085 	ret = io_uring_wait_cqe(ring, &cqe);
1086 	if (ret < 0) {
1087 		fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
1088 		goto err;
1089 	}
1090 
1091 	ret = cqe->res;
1092 	if (ret == -ENOENT)
1093 		ret = 0;
1094 	io_uring_cqe_seen(ring, cqe);
1095 	return ret;
1096 err:
1097 	return 1;
1098 }
1099 
test_update_invalid_flags(struct io_uring * ring)1100 static int test_update_invalid_flags(struct io_uring *ring)
1101 {
1102 	struct io_uring_sqe *sqe;
1103 	struct io_uring_cqe *cqe;
1104 	struct __kernel_timespec ts;
1105 	int ret;
1106 
1107 	sqe = io_uring_get_sqe(ring);
1108 	if (!sqe) {
1109 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
1110 		goto err;
1111 	}
1112 	io_uring_prep_timeout_remove(sqe, 0, IORING_TIMEOUT_ABS);
1113 
1114 	ret = io_uring_submit(ring);
1115 	if (ret != 1) {
1116 		fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
1117 		goto err;
1118 	}
1119 
1120 	ret = io_uring_wait_cqe(ring, &cqe);
1121 	if (ret < 0) {
1122 		fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
1123 		goto err;
1124 	}
1125 	if (cqe->res != -EINVAL) {
1126 		fprintf(stderr, "%s: got %d, wanted %d\n",
1127 				__FUNCTION__, cqe->res, -EINVAL);
1128 		goto err;
1129 	}
1130 	io_uring_cqe_seen(ring, cqe);
1131 
1132 
1133 	sqe = io_uring_get_sqe(ring);
1134 	if (!sqe) {
1135 		fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
1136 		goto err;
1137 	}
1138 	msec_to_ts(&ts, 0);
1139 	io_uring_prep_timeout_update(sqe, &ts, 0, -1);
1140 
1141 	ret = io_uring_submit(ring);
1142 	if (ret != 1) {
1143 		fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
1144 		goto err;
1145 	}
1146 
1147 	ret = io_uring_wait_cqe(ring, &cqe);
1148 	if (ret < 0) {
1149 		fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
1150 		goto err;
1151 	}
1152 	if (cqe->res != -EINVAL) {
1153 		fprintf(stderr, "%s: got %d, wanted %d\n",
1154 				__FUNCTION__, cqe->res, -EINVAL);
1155 		goto err;
1156 	}
1157 	io_uring_cqe_seen(ring, cqe);
1158 
1159 	return 0;
1160 err:
1161 	return 1;
1162 }
1163 
main(int argc,char * argv[])1164 int main(int argc, char *argv[])
1165 {
1166 	struct io_uring ring, sqpoll_ring;
1167 	bool has_timeout_update, sqpoll;
1168 	int ret;
1169 
1170 	if (argc > 1)
1171 		return 0;
1172 
1173 	ret = io_uring_queue_init(8, &ring, 0);
1174 	if (ret) {
1175 		fprintf(stderr, "ring setup failed\n");
1176 		return 1;
1177 	}
1178 
1179 	ret = io_uring_queue_init(8, &sqpoll_ring, IORING_SETUP_SQPOLL);
1180 	sqpoll = !ret;
1181 
1182 	ret = test_single_timeout(&ring);
1183 	if (ret) {
1184 		fprintf(stderr, "test_single_timeout failed\n");
1185 		return ret;
1186 	}
1187 	if (not_supported)
1188 		return 0;
1189 
1190 	ret = test_multi_timeout(&ring);
1191 	if (ret) {
1192 		fprintf(stderr, "test_multi_timeout failed\n");
1193 		return ret;
1194 	}
1195 
1196 	ret = test_single_timeout_abs(&ring);
1197 	if (ret) {
1198 		fprintf(stderr, "test_single_timeout_abs failed\n");
1199 		return ret;
1200 	}
1201 
1202 	ret = test_single_timeout_remove(&ring);
1203 	if (ret) {
1204 		fprintf(stderr, "test_single_timeout_remove failed\n");
1205 		return ret;
1206 	}
1207 
1208 	ret = test_single_timeout_remove_notfound(&ring);
1209 	if (ret) {
1210 		fprintf(stderr, "test_single_timeout_remove_notfound failed\n");
1211 		return ret;
1212 	}
1213 
1214 	ret = test_single_timeout_many(&ring);
1215 	if (ret) {
1216 		fprintf(stderr, "test_single_timeout_many failed\n");
1217 		return ret;
1218 	}
1219 
1220 	ret = test_single_timeout_nr(&ring, 1);
1221 	if (ret) {
1222 		fprintf(stderr, "test_single_timeout_nr(1) failed\n");
1223 		return ret;
1224 	}
1225 	ret = test_single_timeout_nr(&ring, 2);
1226 	if (ret) {
1227 		fprintf(stderr, "test_single_timeout_nr(2) failed\n");
1228 		return ret;
1229 	}
1230 
1231 	ret = test_multi_timeout_nr(&ring);
1232 	if (ret) {
1233 		fprintf(stderr, "test_multi_timeout_nr failed\n");
1234 		return ret;
1235 	}
1236 
1237 	ret = test_timeout_flags1(&ring);
1238 	if (ret) {
1239 		fprintf(stderr, "test_timeout_flags1 failed\n");
1240 		return ret;
1241 	}
1242 
1243 	ret = test_timeout_flags2(&ring);
1244 	if (ret) {
1245 		fprintf(stderr, "test_timeout_flags2 failed\n");
1246 		return ret;
1247 	}
1248 
1249 	ret = test_timeout_flags3(&ring);
1250 	if (ret) {
1251 		fprintf(stderr, "test_timeout_flags3 failed\n");
1252 		return ret;
1253 	}
1254 
1255 	ret = test_single_timeout_wait(&ring);
1256 	if (ret) {
1257 		fprintf(stderr, "test_single_timeout_wait failed\n");
1258 		return ret;
1259 	}
1260 
1261 	/* io_uring_wait_cqes() may have left a timeout, reinit ring */
1262 	io_uring_queue_exit(&ring);
1263 	ret = io_uring_queue_init(8, &ring, 0);
1264 	if (ret) {
1265 		fprintf(stderr, "ring setup failed\n");
1266 		return 1;
1267 	}
1268 
1269 	ret = test_update_nonexistent_timeout(&ring);
1270 	has_timeout_update = (ret != -EINVAL);
1271 	if (has_timeout_update) {
1272 		if (ret) {
1273 			fprintf(stderr, "test_update_nonexistent_timeout failed\n");
1274 			return ret;
1275 		}
1276 
1277 		ret = test_update_invalid_flags(&ring);
1278 		if (ret) {
1279 			fprintf(stderr, "test_update_invalid_flags failed\n");
1280 			return ret;
1281 		}
1282 
1283 		ret = test_update_timeout(&ring, 0, false, false, false);
1284 		if (ret) {
1285 			fprintf(stderr, "test_update_timeout failed\n");
1286 			return ret;
1287 		}
1288 
1289 		ret = test_update_timeout(&ring, 1, false, false, false);
1290 		if (ret) {
1291 			fprintf(stderr, "test_update_timeout 1ms failed\n");
1292 			return ret;
1293 		}
1294 
1295 		ret = test_update_timeout(&ring, 1000, false, false, false);
1296 		if (ret) {
1297 			fprintf(stderr, "test_update_timeout 1s failed\n");
1298 			return ret;
1299 		}
1300 
1301 		ret = test_update_timeout(&ring, 0, true, true, false);
1302 		if (ret) {
1303 			fprintf(stderr, "test_update_timeout abs failed\n");
1304 			return ret;
1305 		}
1306 
1307 
1308 		ret = test_update_timeout(&ring, 0, false, true, false);
1309 		if (ret) {
1310 			fprintf(stderr, "test_update_timeout async failed\n");
1311 			return ret;
1312 		}
1313 
1314 		ret = test_update_timeout(&ring, 0, false, false, true);
1315 		if (ret) {
1316 			fprintf(stderr, "test_update_timeout linked failed\n");
1317 			return ret;
1318 		}
1319 
1320 		if (sqpoll) {
1321 			ret = test_update_timeout(&sqpoll_ring, 0, false, false,
1322 						  false);
1323 			if (ret) {
1324 				fprintf(stderr, "test_update_timeout sqpoll"
1325 						"failed\n");
1326 				return ret;
1327 			}
1328 		}
1329 	}
1330 
1331 	/*
1332 	 * this test must go last, it kills the ring
1333 	 */
1334 	ret = test_single_timeout_exit(&ring);
1335 	if (ret) {
1336 		fprintf(stderr, "test_single_timeout_exit failed\n");
1337 		return ret;
1338 	}
1339 
1340 	if (sqpoll)
1341 		io_uring_queue_exit(&sqpoll_ring);
1342 	return 0;
1343 }
1344