1 /* SPDX-License-Identifier: MIT */
2 /*
3 * Description: test waiting for more events than what will be posted with
4 * a timeout with DEFER_TASKRUN. All kernels should time out,
5 * but a non-buggy kernel will end up with one CQE available
6 * for reaping. Buggy kernels will not have processed the
7 * task_work and will have 0 events.
8 *
9 */
10 #include <errno.h>
11 #include <stdio.h>
12 #include <unistd.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <pthread.h>
16
17 #include "liburing.h"
18 #include "helpers.h"
19
20 struct d {
21 int fd;
22 };
23
thread_fn(void * data)24 static void *thread_fn(void *data)
25 {
26 struct d *d = data;
27 int ret;
28
29 usleep(100000);
30 ret = write(d->fd, "Hello", 5);
31 if (ret < 0)
32 perror("write");
33 return NULL;
34 }
35
test_poll(struct io_uring * ring)36 static int test_poll(struct io_uring *ring)
37 {
38 struct io_uring_cqe *cqe;
39 struct io_uring_sqe *sqe;
40 struct __kernel_timespec ts;
41 int ret, fds[2], i;
42 pthread_t thread;
43 char buf[32];
44 struct d d;
45 void *tret;
46
47 if (pipe(fds) < 0) {
48 perror("pipe");
49 return 1;
50 }
51 d.fd = fds[1];
52
53 sqe = io_uring_get_sqe(ring);
54 io_uring_prep_read(sqe, fds[0], buf, sizeof(buf), 0);
55
56 pthread_create(&thread, NULL, thread_fn, &d);
57
58 ts.tv_sec = 1;
59 ts.tv_nsec = 0;
60
61 ret = io_uring_submit_and_wait_timeout(ring, &cqe, 2, &ts, NULL);
62 if (ret != 1) {
63 fprintf(stderr, "unexpected wait ret %d\n", ret);
64 return T_EXIT_FAIL;
65 }
66
67 for (i = 0; i < 2; i++) {
68 ret = io_uring_peek_cqe(ring, &cqe);
69 if (ret)
70 break;
71 io_uring_cqe_seen(ring, cqe);
72 }
73
74 if (i != 1) {
75 fprintf(stderr, "Got %d request, expected 1\n", i);
76 return T_EXIT_FAIL;
77 }
78
79 pthread_join(thread, &tret);
80 return T_EXIT_PASS;
81 }
82
test_file(struct io_uring * ring,char * __fname)83 static int test_file(struct io_uring *ring, char *__fname)
84 {
85 struct io_uring_cqe *cqe;
86 struct io_uring_sqe *sqe;
87 struct __kernel_timespec ts;
88 char filename[64], *fname;
89 int fd, ret, i;
90 void *buf;
91
92 if (!__fname) {
93 fname = filename;
94 sprintf(fname, ".defer-tw-timeout.%d", getpid());
95 t_create_file(fname, 128*1024);
96 } else {
97 fname = __fname;
98 }
99
100 fd = open(fname, O_RDONLY | O_DIRECT);
101 if (fd < 0) {
102 if (errno == EINVAL) {
103 if (!__fname)
104 unlink(fname);
105 return T_EXIT_SKIP;
106 }
107 perror("open");
108 if (!__fname)
109 unlink(fname);
110 return T_EXIT_FAIL;
111 }
112
113 if (!__fname)
114 unlink(fname);
115
116 if (posix_memalign(&buf, 4096, 4096)) {
117 close(fd);
118 return T_EXIT_FAIL;
119 }
120
121 sqe = io_uring_get_sqe(ring);
122 io_uring_prep_read(sqe, fd, buf, 4096, 0);
123
124 ts.tv_sec = 1;
125 ts.tv_nsec = 0;
126
127 ret = io_uring_submit_and_wait_timeout(ring, &cqe, 2, &ts, NULL);
128 if (ret != 1) {
129 fprintf(stderr, "unexpected wait ret %d\n", ret);
130 close(fd);
131 return T_EXIT_FAIL;
132 }
133
134 for (i = 0; i < 2; i++) {
135 ret = io_uring_peek_cqe(ring, &cqe);
136 if (ret)
137 break;
138 io_uring_cqe_seen(ring, cqe);
139 }
140
141 if (i != 1) {
142 fprintf(stderr, "Got %d request, expected 1\n", i);
143 close(fd);
144 return T_EXIT_FAIL;
145 }
146
147 close(fd);
148 return T_EXIT_PASS;
149 }
150
main(int argc,char * argv[])151 int main(int argc, char *argv[])
152 {
153 struct io_uring ring;
154 char *fname = NULL;
155 int ret;
156
157 ret = io_uring_queue_init(8, &ring, IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN);
158 if (ret == -EINVAL)
159 return T_EXIT_SKIP;
160
161 if (argc > 1)
162 fname = argv[1];
163
164 ret = test_file(&ring, fname);
165 if (ret != T_EXIT_PASS)
166 return ret;
167
168 ret = test_poll(&ring);
169 if (ret != T_EXIT_PASS)
170 return ret;
171
172 return T_EXIT_PASS;
173 }
174