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