xref: /aosp_15_r20/external/liburing/test/multicqes_drain.c (revision 25da2bea747f3a93b4c30fd9708b0618ef55a0e6)
1*25da2beaSAndroid Build Coastguard Worker /* SPDX-License-Identifier: MIT */
2*25da2beaSAndroid Build Coastguard Worker /*
3*25da2beaSAndroid Build Coastguard Worker  * Description: generic tests for  io_uring drain io
4*25da2beaSAndroid Build Coastguard Worker  *
5*25da2beaSAndroid Build Coastguard Worker  * The main idea is to randomly generate different type of sqe to
6*25da2beaSAndroid Build Coastguard Worker  * challenge the drain logic. There are some restrictions for the
7*25da2beaSAndroid Build Coastguard Worker  * generated sqes, details in io_uring maillist:
8*25da2beaSAndroid Build Coastguard Worker  * https://lore.kernel.org/io-uring/[email protected]/
9*25da2beaSAndroid Build Coastguard Worker  *
10*25da2beaSAndroid Build Coastguard Worker  */
11*25da2beaSAndroid Build Coastguard Worker #include <errno.h>
12*25da2beaSAndroid Build Coastguard Worker #include <stdio.h>
13*25da2beaSAndroid Build Coastguard Worker #include <unistd.h>
14*25da2beaSAndroid Build Coastguard Worker #include <stdlib.h>
15*25da2beaSAndroid Build Coastguard Worker #include <string.h>
16*25da2beaSAndroid Build Coastguard Worker #include <time.h>
17*25da2beaSAndroid Build Coastguard Worker #include <poll.h>
18*25da2beaSAndroid Build Coastguard Worker 
19*25da2beaSAndroid Build Coastguard Worker #include "liburing.h"
20*25da2beaSAndroid Build Coastguard Worker 
21*25da2beaSAndroid Build Coastguard Worker enum {
22*25da2beaSAndroid Build Coastguard Worker 	multi,
23*25da2beaSAndroid Build Coastguard Worker 	single,
24*25da2beaSAndroid Build Coastguard Worker 	nop,
25*25da2beaSAndroid Build Coastguard Worker 	cancel,
26*25da2beaSAndroid Build Coastguard Worker 	op_last,
27*25da2beaSAndroid Build Coastguard Worker };
28*25da2beaSAndroid Build Coastguard Worker 
29*25da2beaSAndroid Build Coastguard Worker struct sqe_info {
30*25da2beaSAndroid Build Coastguard Worker 	__u8 op;
31*25da2beaSAndroid Build Coastguard Worker 	unsigned flags;
32*25da2beaSAndroid Build Coastguard Worker };
33*25da2beaSAndroid Build Coastguard Worker 
34*25da2beaSAndroid Build Coastguard Worker #define max_entry 50
35*25da2beaSAndroid Build Coastguard Worker 
36*25da2beaSAndroid Build Coastguard Worker /*
37*25da2beaSAndroid Build Coastguard Worker  * sqe_flags: combination of sqe flags
38*25da2beaSAndroid Build Coastguard Worker  * multi_sqes: record the user_data/index of all the multishot sqes
39*25da2beaSAndroid Build Coastguard Worker  * cnt: how many entries there are in multi_sqes
40*25da2beaSAndroid Build Coastguard Worker  * we can leverage multi_sqes array for cancellation: we randomly pick
41*25da2beaSAndroid Build Coastguard Worker  * up an entry in multi_sqes when form a cancellation sqe.
42*25da2beaSAndroid Build Coastguard Worker  * multi_cap: limitation of number of multishot sqes
43*25da2beaSAndroid Build Coastguard Worker  */
44*25da2beaSAndroid Build Coastguard Worker const unsigned sqe_flags[4] = {0, IOSQE_IO_LINK, IOSQE_IO_DRAIN,
45*25da2beaSAndroid Build Coastguard Worker 	IOSQE_IO_LINK | IOSQE_IO_DRAIN};
46*25da2beaSAndroid Build Coastguard Worker int multi_sqes[max_entry], cnt = 0;
47*25da2beaSAndroid Build Coastguard Worker int multi_cap = max_entry / 5;
48*25da2beaSAndroid Build Coastguard Worker 
write_pipe(int pipe,char * str)49*25da2beaSAndroid Build Coastguard Worker int write_pipe(int pipe, char *str)
50*25da2beaSAndroid Build Coastguard Worker {
51*25da2beaSAndroid Build Coastguard Worker 	int ret;
52*25da2beaSAndroid Build Coastguard Worker 	do {
53*25da2beaSAndroid Build Coastguard Worker 		errno = 0;
54*25da2beaSAndroid Build Coastguard Worker 		ret = write(pipe, str, 3);
55*25da2beaSAndroid Build Coastguard Worker 	} while (ret == -1 && errno == EINTR);
56*25da2beaSAndroid Build Coastguard Worker 	return ret;
57*25da2beaSAndroid Build Coastguard Worker }
58*25da2beaSAndroid Build Coastguard Worker 
read_pipe(int pipe)59*25da2beaSAndroid Build Coastguard Worker void read_pipe(int pipe)
60*25da2beaSAndroid Build Coastguard Worker {
61*25da2beaSAndroid Build Coastguard Worker 	char str[4] = {0};
62*25da2beaSAndroid Build Coastguard Worker 	int ret;
63*25da2beaSAndroid Build Coastguard Worker 
64*25da2beaSAndroid Build Coastguard Worker 	ret = read(pipe, &str, 3);
65*25da2beaSAndroid Build Coastguard Worker 	if (ret < 0)
66*25da2beaSAndroid Build Coastguard Worker 		perror("read");
67*25da2beaSAndroid Build Coastguard Worker }
68*25da2beaSAndroid Build Coastguard Worker 
trigger_event(int p[])69*25da2beaSAndroid Build Coastguard Worker int trigger_event(int p[])
70*25da2beaSAndroid Build Coastguard Worker {
71*25da2beaSAndroid Build Coastguard Worker 	int ret;
72*25da2beaSAndroid Build Coastguard Worker 	if ((ret = write_pipe(p[1], "foo")) != 3) {
73*25da2beaSAndroid Build Coastguard Worker 		fprintf(stderr, "bad write return %d\n", ret);
74*25da2beaSAndroid Build Coastguard Worker 		return 1;
75*25da2beaSAndroid Build Coastguard Worker 	}
76*25da2beaSAndroid Build Coastguard Worker 	read_pipe(p[0]);
77*25da2beaSAndroid Build Coastguard Worker 	return 0;
78*25da2beaSAndroid Build Coastguard Worker }
79*25da2beaSAndroid Build Coastguard Worker 
io_uring_sqe_prep(int op,struct io_uring_sqe * sqe,unsigned sqe_flags,int arg)80*25da2beaSAndroid Build Coastguard Worker void io_uring_sqe_prep(int op, struct io_uring_sqe *sqe, unsigned sqe_flags, int arg)
81*25da2beaSAndroid Build Coastguard Worker {
82*25da2beaSAndroid Build Coastguard Worker 	switch (op) {
83*25da2beaSAndroid Build Coastguard Worker 		case multi:
84*25da2beaSAndroid Build Coastguard Worker 			io_uring_prep_poll_add(sqe, arg, POLLIN);
85*25da2beaSAndroid Build Coastguard Worker 			sqe->len |= IORING_POLL_ADD_MULTI;
86*25da2beaSAndroid Build Coastguard Worker 			break;
87*25da2beaSAndroid Build Coastguard Worker 		case single:
88*25da2beaSAndroid Build Coastguard Worker 			io_uring_prep_poll_add(sqe, arg, POLLIN);
89*25da2beaSAndroid Build Coastguard Worker 			break;
90*25da2beaSAndroid Build Coastguard Worker 		case nop:
91*25da2beaSAndroid Build Coastguard Worker 			io_uring_prep_nop(sqe);
92*25da2beaSAndroid Build Coastguard Worker 			break;
93*25da2beaSAndroid Build Coastguard Worker 		case cancel:
94*25da2beaSAndroid Build Coastguard Worker 			io_uring_prep_poll_remove(sqe, arg);
95*25da2beaSAndroid Build Coastguard Worker 			break;
96*25da2beaSAndroid Build Coastguard Worker 	}
97*25da2beaSAndroid Build Coastguard Worker 	sqe->flags = sqe_flags;
98*25da2beaSAndroid Build Coastguard Worker }
99*25da2beaSAndroid Build Coastguard Worker 
generate_flags(int sqe_op)100*25da2beaSAndroid Build Coastguard Worker __u8 generate_flags(int sqe_op)
101*25da2beaSAndroid Build Coastguard Worker {
102*25da2beaSAndroid Build Coastguard Worker 	__u8 flags = 0;
103*25da2beaSAndroid Build Coastguard Worker 	/*
104*25da2beaSAndroid Build Coastguard Worker 	 * drain sqe must be put after multishot sqes cancelled
105*25da2beaSAndroid Build Coastguard Worker 	 */
106*25da2beaSAndroid Build Coastguard Worker 	do {
107*25da2beaSAndroid Build Coastguard Worker 		flags = sqe_flags[rand() % 4];
108*25da2beaSAndroid Build Coastguard Worker 	} while ((flags & IOSQE_IO_DRAIN) && cnt);
109*25da2beaSAndroid Build Coastguard Worker 
110*25da2beaSAndroid Build Coastguard Worker 	/*
111*25da2beaSAndroid Build Coastguard Worker 	 * cancel req cannot have drain or link flag
112*25da2beaSAndroid Build Coastguard Worker 	 */
113*25da2beaSAndroid Build Coastguard Worker 	if (sqe_op == cancel) {
114*25da2beaSAndroid Build Coastguard Worker 		flags &= ~(IOSQE_IO_DRAIN | IOSQE_IO_LINK);
115*25da2beaSAndroid Build Coastguard Worker 	}
116*25da2beaSAndroid Build Coastguard Worker 	/*
117*25da2beaSAndroid Build Coastguard Worker 	 * avoid below case:
118*25da2beaSAndroid Build Coastguard Worker 	 * sqe0(multishot, link)->sqe1(nop, link)->sqe2(nop)->sqe3(cancel_sqe0)
119*25da2beaSAndroid Build Coastguard Worker 	 * sqe3 may excute before sqe0 so that sqe0 isn't cancelled
120*25da2beaSAndroid Build Coastguard Worker 	 */
121*25da2beaSAndroid Build Coastguard Worker 	if (sqe_op == multi)
122*25da2beaSAndroid Build Coastguard Worker 		flags &= ~IOSQE_IO_LINK;
123*25da2beaSAndroid Build Coastguard Worker 
124*25da2beaSAndroid Build Coastguard Worker 	return flags;
125*25da2beaSAndroid Build Coastguard Worker 
126*25da2beaSAndroid Build Coastguard Worker }
127*25da2beaSAndroid Build Coastguard Worker 
128*25da2beaSAndroid Build Coastguard Worker /*
129*25da2beaSAndroid Build Coastguard Worker  * function to generate opcode of a sqe
130*25da2beaSAndroid Build Coastguard Worker  * several restrictions here:
131*25da2beaSAndroid Build Coastguard Worker  * - cancel all the previous multishot sqes as soon as possible when
132*25da2beaSAndroid Build Coastguard Worker  *   we reach high watermark.
133*25da2beaSAndroid Build Coastguard Worker  * - ensure there is some multishot sqe when generating a cancel sqe
134*25da2beaSAndroid Build Coastguard Worker  * - ensure a cancel/multshot sqe is not in a linkchain
135*25da2beaSAndroid Build Coastguard Worker  * - ensure number of multishot sqes doesn't exceed multi_cap
136*25da2beaSAndroid Build Coastguard Worker  * - don't generate multishot sqes after high watermark
137*25da2beaSAndroid Build Coastguard Worker  */
generate_opcode(int i,int pre_flags)138*25da2beaSAndroid Build Coastguard Worker int generate_opcode(int i, int pre_flags)
139*25da2beaSAndroid Build Coastguard Worker {
140*25da2beaSAndroid Build Coastguard Worker 	int sqe_op;
141*25da2beaSAndroid Build Coastguard Worker 	int high_watermark = max_entry - max_entry / 5;
142*25da2beaSAndroid Build Coastguard Worker 	bool retry0 = false, retry1 = false, retry2 = false;
143*25da2beaSAndroid Build Coastguard Worker 
144*25da2beaSAndroid Build Coastguard Worker 	if ((i >= high_watermark) && cnt) {
145*25da2beaSAndroid Build Coastguard Worker 		sqe_op = cancel;
146*25da2beaSAndroid Build Coastguard Worker 	} else {
147*25da2beaSAndroid Build Coastguard Worker 		do {
148*25da2beaSAndroid Build Coastguard Worker 			sqe_op = rand() % op_last;
149*25da2beaSAndroid Build Coastguard Worker 			retry0 = (sqe_op == cancel) && (!cnt || (pre_flags & IOSQE_IO_LINK));
150*25da2beaSAndroid Build Coastguard Worker 			retry1 = (sqe_op == multi) && ((multi_cap - 1 < 0) || i >= high_watermark);
151*25da2beaSAndroid Build Coastguard Worker 			retry2 = (sqe_op == multi) && (pre_flags & IOSQE_IO_LINK);
152*25da2beaSAndroid Build Coastguard Worker 		} while (retry0 || retry1 || retry2);
153*25da2beaSAndroid Build Coastguard Worker 	}
154*25da2beaSAndroid Build Coastguard Worker 
155*25da2beaSAndroid Build Coastguard Worker 	if (sqe_op == multi)
156*25da2beaSAndroid Build Coastguard Worker 		multi_cap--;
157*25da2beaSAndroid Build Coastguard Worker 	return sqe_op;
158*25da2beaSAndroid Build Coastguard Worker }
159*25da2beaSAndroid Build Coastguard Worker 
add_multishot_sqe(int index)160*25da2beaSAndroid Build Coastguard Worker static inline void add_multishot_sqe(int index)
161*25da2beaSAndroid Build Coastguard Worker {
162*25da2beaSAndroid Build Coastguard Worker 	multi_sqes[cnt++] = index;
163*25da2beaSAndroid Build Coastguard Worker }
164*25da2beaSAndroid Build Coastguard Worker 
remove_multishot_sqe()165*25da2beaSAndroid Build Coastguard Worker int remove_multishot_sqe()
166*25da2beaSAndroid Build Coastguard Worker {
167*25da2beaSAndroid Build Coastguard Worker 	int ret;
168*25da2beaSAndroid Build Coastguard Worker 
169*25da2beaSAndroid Build Coastguard Worker 	int rem_index = rand() % cnt;
170*25da2beaSAndroid Build Coastguard Worker 	ret = multi_sqes[rem_index];
171*25da2beaSAndroid Build Coastguard Worker 	multi_sqes[rem_index] = multi_sqes[cnt - 1];
172*25da2beaSAndroid Build Coastguard Worker 	cnt--;
173*25da2beaSAndroid Build Coastguard Worker 
174*25da2beaSAndroid Build Coastguard Worker 	return ret;
175*25da2beaSAndroid Build Coastguard Worker }
176*25da2beaSAndroid Build Coastguard Worker 
test_generic_drain(struct io_uring * ring)177*25da2beaSAndroid Build Coastguard Worker static int test_generic_drain(struct io_uring *ring)
178*25da2beaSAndroid Build Coastguard Worker {
179*25da2beaSAndroid Build Coastguard Worker 	struct io_uring_cqe *cqe;
180*25da2beaSAndroid Build Coastguard Worker 	struct io_uring_sqe *sqe[max_entry];
181*25da2beaSAndroid Build Coastguard Worker 	struct sqe_info si[max_entry];
182*25da2beaSAndroid Build Coastguard Worker 	int cqe_data[max_entry << 1], cqe_res[max_entry << 1];
183*25da2beaSAndroid Build Coastguard Worker 	int i, j, ret, arg = 0;
184*25da2beaSAndroid Build Coastguard Worker 	int pipes[max_entry][2];
185*25da2beaSAndroid Build Coastguard Worker 	int pre_flags = 0;
186*25da2beaSAndroid Build Coastguard Worker 
187*25da2beaSAndroid Build Coastguard Worker 	for (i = 0; i < max_entry; i++) {
188*25da2beaSAndroid Build Coastguard Worker 		if (pipe(pipes[i]) != 0) {
189*25da2beaSAndroid Build Coastguard Worker 			perror("pipe");
190*25da2beaSAndroid Build Coastguard Worker 			return 1;
191*25da2beaSAndroid Build Coastguard Worker 		}
192*25da2beaSAndroid Build Coastguard Worker 	}
193*25da2beaSAndroid Build Coastguard Worker 
194*25da2beaSAndroid Build Coastguard Worker 	srand((unsigned)time(NULL));
195*25da2beaSAndroid Build Coastguard Worker 	for (i = 0; i < max_entry; i++) {
196*25da2beaSAndroid Build Coastguard Worker 		sqe[i] = io_uring_get_sqe(ring);
197*25da2beaSAndroid Build Coastguard Worker 		if (!sqe[i]) {
198*25da2beaSAndroid Build Coastguard Worker 			printf("get sqe failed\n");
199*25da2beaSAndroid Build Coastguard Worker 			goto err;
200*25da2beaSAndroid Build Coastguard Worker 		}
201*25da2beaSAndroid Build Coastguard Worker 
202*25da2beaSAndroid Build Coastguard Worker 		int sqe_op = generate_opcode(i, pre_flags);
203*25da2beaSAndroid Build Coastguard Worker 		__u8 flags = generate_flags(sqe_op);
204*25da2beaSAndroid Build Coastguard Worker 
205*25da2beaSAndroid Build Coastguard Worker 		if (sqe_op == cancel)
206*25da2beaSAndroid Build Coastguard Worker 			arg = remove_multishot_sqe();
207*25da2beaSAndroid Build Coastguard Worker 		if (sqe_op == multi || sqe_op == single)
208*25da2beaSAndroid Build Coastguard Worker 			arg = pipes[i][0];
209*25da2beaSAndroid Build Coastguard Worker 		io_uring_sqe_prep(sqe_op, sqe[i], flags, arg);
210*25da2beaSAndroid Build Coastguard Worker 		sqe[i]->user_data = i;
211*25da2beaSAndroid Build Coastguard Worker 		si[i].op = sqe_op;
212*25da2beaSAndroid Build Coastguard Worker 		si[i].flags = flags;
213*25da2beaSAndroid Build Coastguard Worker 		pre_flags = flags;
214*25da2beaSAndroid Build Coastguard Worker 		if (sqe_op == multi)
215*25da2beaSAndroid Build Coastguard Worker 			add_multishot_sqe(i);
216*25da2beaSAndroid Build Coastguard Worker 	}
217*25da2beaSAndroid Build Coastguard Worker 
218*25da2beaSAndroid Build Coastguard Worker 	ret = io_uring_submit(ring);
219*25da2beaSAndroid Build Coastguard Worker 	if (ret < 0) {
220*25da2beaSAndroid Build Coastguard Worker 		printf("sqe submit failed\n");
221*25da2beaSAndroid Build Coastguard Worker 		goto err;
222*25da2beaSAndroid Build Coastguard Worker 	} else if (ret < max_entry) {
223*25da2beaSAndroid Build Coastguard Worker 		printf("Submitted only %d\n", ret);
224*25da2beaSAndroid Build Coastguard Worker 		goto err;
225*25da2beaSAndroid Build Coastguard Worker 	}
226*25da2beaSAndroid Build Coastguard Worker 
227*25da2beaSAndroid Build Coastguard Worker 	sleep(1);
228*25da2beaSAndroid Build Coastguard Worker 	// TODO: randomize event triggerring order
229*25da2beaSAndroid Build Coastguard Worker 	for (i = 0; i < max_entry; i++) {
230*25da2beaSAndroid Build Coastguard Worker 		if (si[i].op != multi && si[i].op != single)
231*25da2beaSAndroid Build Coastguard Worker 			continue;
232*25da2beaSAndroid Build Coastguard Worker 
233*25da2beaSAndroid Build Coastguard Worker 		if (trigger_event(pipes[i]))
234*25da2beaSAndroid Build Coastguard Worker 			goto err;
235*25da2beaSAndroid Build Coastguard Worker 	}
236*25da2beaSAndroid Build Coastguard Worker 	sleep(1);
237*25da2beaSAndroid Build Coastguard Worker 	i = 0;
238*25da2beaSAndroid Build Coastguard Worker 	while (!io_uring_peek_cqe(ring, &cqe)) {
239*25da2beaSAndroid Build Coastguard Worker 		cqe_data[i] = cqe->user_data;
240*25da2beaSAndroid Build Coastguard Worker 		cqe_res[i++] = cqe->res;
241*25da2beaSAndroid Build Coastguard Worker 		io_uring_cqe_seen(ring, cqe);
242*25da2beaSAndroid Build Coastguard Worker 	}
243*25da2beaSAndroid Build Coastguard Worker 
244*25da2beaSAndroid Build Coastguard Worker 	/*
245*25da2beaSAndroid Build Coastguard Worker 	 * compl_bits is a bit map to record completions.
246*25da2beaSAndroid Build Coastguard Worker 	 * eg. sqe[0], sqe[1], sqe[2] fully completed
247*25da2beaSAndroid Build Coastguard Worker 	 * then compl_bits is 000...00111b
248*25da2beaSAndroid Build Coastguard Worker 	 *
249*25da2beaSAndroid Build Coastguard Worker 	 */
250*25da2beaSAndroid Build Coastguard Worker 	unsigned long long compl_bits = 0;
251*25da2beaSAndroid Build Coastguard Worker 	for (j = 0; j < i; j++) {
252*25da2beaSAndroid Build Coastguard Worker 		int index = cqe_data[j];
253*25da2beaSAndroid Build Coastguard Worker 		if ((si[index].flags & IOSQE_IO_DRAIN) && index) {
254*25da2beaSAndroid Build Coastguard Worker 			if ((~compl_bits) & ((1ULL << index) - 1)) {
255*25da2beaSAndroid Build Coastguard Worker 				printf("drain failed\n");
256*25da2beaSAndroid Build Coastguard Worker 				goto err;
257*25da2beaSAndroid Build Coastguard Worker 			}
258*25da2beaSAndroid Build Coastguard Worker 		}
259*25da2beaSAndroid Build Coastguard Worker 		/*
260*25da2beaSAndroid Build Coastguard Worker 		 * for multishot sqes, record them only when it is cancelled
261*25da2beaSAndroid Build Coastguard Worker 		 */
262*25da2beaSAndroid Build Coastguard Worker 		if ((si[index].op != multi) || (cqe_res[j] == -ECANCELED))
263*25da2beaSAndroid Build Coastguard Worker 			compl_bits |= (1ULL << index);
264*25da2beaSAndroid Build Coastguard Worker 	}
265*25da2beaSAndroid Build Coastguard Worker 
266*25da2beaSAndroid Build Coastguard Worker 	return 0;
267*25da2beaSAndroid Build Coastguard Worker err:
268*25da2beaSAndroid Build Coastguard Worker 	return 1;
269*25da2beaSAndroid Build Coastguard Worker }
270*25da2beaSAndroid Build Coastguard Worker 
test_simple_drain(struct io_uring * ring)271*25da2beaSAndroid Build Coastguard Worker static int test_simple_drain(struct io_uring *ring)
272*25da2beaSAndroid Build Coastguard Worker {
273*25da2beaSAndroid Build Coastguard Worker 	struct io_uring_cqe *cqe;
274*25da2beaSAndroid Build Coastguard Worker 	struct io_uring_sqe *sqe[2];
275*25da2beaSAndroid Build Coastguard Worker 	int i, ret;
276*25da2beaSAndroid Build Coastguard Worker 	int pipe1[2], pipe2[2];
277*25da2beaSAndroid Build Coastguard Worker 
278*25da2beaSAndroid Build Coastguard Worker 	if (pipe(pipe1) != 0 || pipe(pipe2) != 0) {
279*25da2beaSAndroid Build Coastguard Worker 		perror("pipe");
280*25da2beaSAndroid Build Coastguard Worker 		return 1;
281*25da2beaSAndroid Build Coastguard Worker 	}
282*25da2beaSAndroid Build Coastguard Worker 
283*25da2beaSAndroid Build Coastguard Worker 	for (i = 0; i < 2; i++) {
284*25da2beaSAndroid Build Coastguard Worker 		sqe[i] = io_uring_get_sqe(ring);
285*25da2beaSAndroid Build Coastguard Worker 		if (!sqe[i]) {
286*25da2beaSAndroid Build Coastguard Worker 			printf("get sqe failed\n");
287*25da2beaSAndroid Build Coastguard Worker 			goto err;
288*25da2beaSAndroid Build Coastguard Worker 		}
289*25da2beaSAndroid Build Coastguard Worker 	}
290*25da2beaSAndroid Build Coastguard Worker 
291*25da2beaSAndroid Build Coastguard Worker 	io_uring_prep_poll_multishot(sqe[0], pipe1[0], POLLIN);
292*25da2beaSAndroid Build Coastguard Worker 	sqe[0]->user_data = 0;
293*25da2beaSAndroid Build Coastguard Worker 
294*25da2beaSAndroid Build Coastguard Worker 	io_uring_prep_poll_add(sqe[1], pipe2[0], POLLIN);
295*25da2beaSAndroid Build Coastguard Worker 	sqe[1]->user_data = 1;
296*25da2beaSAndroid Build Coastguard Worker 
297*25da2beaSAndroid Build Coastguard Worker 	ret = io_uring_submit(ring);
298*25da2beaSAndroid Build Coastguard Worker 	if (ret < 0) {
299*25da2beaSAndroid Build Coastguard Worker 		printf("sqe submit failed\n");
300*25da2beaSAndroid Build Coastguard Worker 		goto err;
301*25da2beaSAndroid Build Coastguard Worker 	} else if (ret < 2) {
302*25da2beaSAndroid Build Coastguard Worker 		printf("Submitted only %d\n", ret);
303*25da2beaSAndroid Build Coastguard Worker 		goto err;
304*25da2beaSAndroid Build Coastguard Worker 	}
305*25da2beaSAndroid Build Coastguard Worker 
306*25da2beaSAndroid Build Coastguard Worker 	for (i = 0; i < 2; i++) {
307*25da2beaSAndroid Build Coastguard Worker 		if (trigger_event(pipe1))
308*25da2beaSAndroid Build Coastguard Worker 			goto err;
309*25da2beaSAndroid Build Coastguard Worker 	}
310*25da2beaSAndroid Build Coastguard Worker 	if (trigger_event(pipe2))
311*25da2beaSAndroid Build Coastguard Worker 			goto err;
312*25da2beaSAndroid Build Coastguard Worker 
313*25da2beaSAndroid Build Coastguard Worker 	for (i = 0; i < 2; i++) {
314*25da2beaSAndroid Build Coastguard Worker 		sqe[i] = io_uring_get_sqe(ring);
315*25da2beaSAndroid Build Coastguard Worker 		if (!sqe[i]) {
316*25da2beaSAndroid Build Coastguard Worker 			printf("get sqe failed\n");
317*25da2beaSAndroid Build Coastguard Worker 			goto err;
318*25da2beaSAndroid Build Coastguard Worker 		}
319*25da2beaSAndroid Build Coastguard Worker 	}
320*25da2beaSAndroid Build Coastguard Worker 
321*25da2beaSAndroid Build Coastguard Worker 	io_uring_prep_poll_remove(sqe[0], 0);
322*25da2beaSAndroid Build Coastguard Worker 	sqe[0]->user_data = 2;
323*25da2beaSAndroid Build Coastguard Worker 
324*25da2beaSAndroid Build Coastguard Worker 	io_uring_prep_nop(sqe[1]);
325*25da2beaSAndroid Build Coastguard Worker 	sqe[1]->flags |= IOSQE_IO_DRAIN;
326*25da2beaSAndroid Build Coastguard Worker 	sqe[1]->user_data = 3;
327*25da2beaSAndroid Build Coastguard Worker 
328*25da2beaSAndroid Build Coastguard Worker 	ret = io_uring_submit(ring);
329*25da2beaSAndroid Build Coastguard Worker 	if (ret < 0) {
330*25da2beaSAndroid Build Coastguard Worker 		printf("sqe submit failed\n");
331*25da2beaSAndroid Build Coastguard Worker 		goto err;
332*25da2beaSAndroid Build Coastguard Worker 	} else if (ret < 2) {
333*25da2beaSAndroid Build Coastguard Worker 		printf("Submitted only %d\n", ret);
334*25da2beaSAndroid Build Coastguard Worker 		goto err;
335*25da2beaSAndroid Build Coastguard Worker 	}
336*25da2beaSAndroid Build Coastguard Worker 
337*25da2beaSAndroid Build Coastguard Worker 	for (i = 0; i < 6; i++) {
338*25da2beaSAndroid Build Coastguard Worker 		ret = io_uring_wait_cqe(ring, &cqe);
339*25da2beaSAndroid Build Coastguard Worker 		if (ret < 0) {
340*25da2beaSAndroid Build Coastguard Worker 			printf("wait completion %d\n", ret);
341*25da2beaSAndroid Build Coastguard Worker 			goto err;
342*25da2beaSAndroid Build Coastguard Worker 		}
343*25da2beaSAndroid Build Coastguard Worker 		if ((i == 5) && (cqe->user_data != 3))
344*25da2beaSAndroid Build Coastguard Worker 			goto err;
345*25da2beaSAndroid Build Coastguard Worker 		io_uring_cqe_seen(ring, cqe);
346*25da2beaSAndroid Build Coastguard Worker 	}
347*25da2beaSAndroid Build Coastguard Worker 
348*25da2beaSAndroid Build Coastguard Worker 	close(pipe1[0]);
349*25da2beaSAndroid Build Coastguard Worker 	close(pipe1[1]);
350*25da2beaSAndroid Build Coastguard Worker 	close(pipe2[0]);
351*25da2beaSAndroid Build Coastguard Worker 	close(pipe2[1]);
352*25da2beaSAndroid Build Coastguard Worker 	return 0;
353*25da2beaSAndroid Build Coastguard Worker err:
354*25da2beaSAndroid Build Coastguard Worker 	return 1;
355*25da2beaSAndroid Build Coastguard Worker }
356*25da2beaSAndroid Build Coastguard Worker 
main(int argc,char * argv[])357*25da2beaSAndroid Build Coastguard Worker int main(int argc, char *argv[])
358*25da2beaSAndroid Build Coastguard Worker {
359*25da2beaSAndroid Build Coastguard Worker 	struct io_uring ring;
360*25da2beaSAndroid Build Coastguard Worker 	int i, ret;
361*25da2beaSAndroid Build Coastguard Worker 
362*25da2beaSAndroid Build Coastguard Worker 	if (argc > 1)
363*25da2beaSAndroid Build Coastguard Worker 		return 0;
364*25da2beaSAndroid Build Coastguard Worker 
365*25da2beaSAndroid Build Coastguard Worker 	ret = io_uring_queue_init(1024, &ring, 0);
366*25da2beaSAndroid Build Coastguard Worker 	if (ret) {
367*25da2beaSAndroid Build Coastguard Worker 		printf("ring setup failed\n");
368*25da2beaSAndroid Build Coastguard Worker 		return 1;
369*25da2beaSAndroid Build Coastguard Worker 	}
370*25da2beaSAndroid Build Coastguard Worker 
371*25da2beaSAndroid Build Coastguard Worker 	for (i = 0; i < 5; i++) {
372*25da2beaSAndroid Build Coastguard Worker 		ret = test_simple_drain(&ring);
373*25da2beaSAndroid Build Coastguard Worker 		if (ret) {
374*25da2beaSAndroid Build Coastguard Worker 			fprintf(stderr, "test_simple_drain failed\n");
375*25da2beaSAndroid Build Coastguard Worker 			break;
376*25da2beaSAndroid Build Coastguard Worker 		}
377*25da2beaSAndroid Build Coastguard Worker 	}
378*25da2beaSAndroid Build Coastguard Worker 
379*25da2beaSAndroid Build Coastguard Worker 	for (i = 0; i < 5; i++) {
380*25da2beaSAndroid Build Coastguard Worker 		ret = test_generic_drain(&ring);
381*25da2beaSAndroid Build Coastguard Worker 		if (ret) {
382*25da2beaSAndroid Build Coastguard Worker 			fprintf(stderr, "test_generic_drain failed\n");
383*25da2beaSAndroid Build Coastguard Worker 			break;
384*25da2beaSAndroid Build Coastguard Worker 		}
385*25da2beaSAndroid Build Coastguard Worker 	}
386*25da2beaSAndroid Build Coastguard Worker 	return ret;
387*25da2beaSAndroid Build Coastguard Worker }
388