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 || errno == EPERM || errno == EACCES) {
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 free(buf);
132 return T_EXIT_FAIL;
133 }
134
135 for (i = 0; i < 2; i++) {
136 ret = io_uring_peek_cqe(ring, &cqe);
137 if (ret)
138 break;
139 io_uring_cqe_seen(ring, cqe);
140 }
141
142 if (i != 1) {
143 fprintf(stderr, "Got %d request, expected 1\n", i);
144 close(fd);
145 free(buf);
146 return T_EXIT_FAIL;
147 }
148
149 close(fd);
150 free(buf);
151 return T_EXIT_PASS;
152 }
153
main(int argc,char * argv[])154 int main(int argc, char *argv[])
155 {
156 struct io_uring ring;
157 char *fname = NULL;
158 int ret;
159
160 ret = io_uring_queue_init(8, &ring, IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN);
161 if (ret == -EINVAL)
162 return T_EXIT_SKIP;
163
164 if (argc > 1)
165 fname = argv[1];
166
167 ret = test_file(&ring, fname);
168 if (ret != T_EXIT_PASS)
169 return ret;
170
171 ret = test_poll(&ring);
172 if (ret != T_EXIT_PASS)
173 return ret;
174
175 return T_EXIT_PASS;
176 }
177