xref: /aosp_15_r20/external/liburing/examples/ucontext-cp.c (revision 25da2bea747f3a93b4c30fd9708b0618ef55a0e6)
1*25da2beaSAndroid Build Coastguard Worker /* SPDX-License-Identifier: MIT */
2*25da2beaSAndroid Build Coastguard Worker /*
3*25da2beaSAndroid Build Coastguard Worker  * gcc -Wall -O2 -D_GNU_SOURCE -o ucontext-cp ucontext-cp.c -luring
4*25da2beaSAndroid Build Coastguard Worker  */
5*25da2beaSAndroid Build Coastguard Worker #define _POSIX_C_SOURCE 199309L
6*25da2beaSAndroid Build Coastguard Worker #include <stdio.h>
7*25da2beaSAndroid Build Coastguard Worker #include <fcntl.h>
8*25da2beaSAndroid Build Coastguard Worker #include <string.h>
9*25da2beaSAndroid Build Coastguard Worker #include <stdlib.h>
10*25da2beaSAndroid Build Coastguard Worker #include <unistd.h>
11*25da2beaSAndroid Build Coastguard Worker #include <assert.h>
12*25da2beaSAndroid Build Coastguard Worker #include <errno.h>
13*25da2beaSAndroid Build Coastguard Worker #include <ucontext.h>
14*25da2beaSAndroid Build Coastguard Worker #include <signal.h>
15*25da2beaSAndroid Build Coastguard Worker #include <inttypes.h>
16*25da2beaSAndroid Build Coastguard Worker #include <sys/types.h>
17*25da2beaSAndroid Build Coastguard Worker #include <sys/ioctl.h>
18*25da2beaSAndroid Build Coastguard Worker #include <sys/timerfd.h>
19*25da2beaSAndroid Build Coastguard Worker #include <poll.h>
20*25da2beaSAndroid Build Coastguard Worker #include "liburing.h"
21*25da2beaSAndroid Build Coastguard Worker 
22*25da2beaSAndroid Build Coastguard Worker #define QD	64
23*25da2beaSAndroid Build Coastguard Worker #define BS	1024
24*25da2beaSAndroid Build Coastguard Worker 
25*25da2beaSAndroid Build Coastguard Worker #ifndef SIGSTKSZ
26*25da2beaSAndroid Build Coastguard Worker #define SIGSTKSZ 8192
27*25da2beaSAndroid Build Coastguard Worker #endif
28*25da2beaSAndroid Build Coastguard Worker 
29*25da2beaSAndroid Build Coastguard Worker typedef struct {
30*25da2beaSAndroid Build Coastguard Worker 	struct io_uring *ring;
31*25da2beaSAndroid Build Coastguard Worker 	unsigned char *stack_buf;
32*25da2beaSAndroid Build Coastguard Worker 	ucontext_t ctx_main, ctx_fnew;
33*25da2beaSAndroid Build Coastguard Worker } async_context;
34*25da2beaSAndroid Build Coastguard Worker 
35*25da2beaSAndroid Build Coastguard Worker typedef struct {
36*25da2beaSAndroid Build Coastguard Worker 	async_context *pctx;
37*25da2beaSAndroid Build Coastguard Worker 	int *psuccess;
38*25da2beaSAndroid Build Coastguard Worker 	int *pfailure;
39*25da2beaSAndroid Build Coastguard Worker 	int infd;
40*25da2beaSAndroid Build Coastguard Worker 	int outfd;
41*25da2beaSAndroid Build Coastguard Worker } arguments_bundle;
42*25da2beaSAndroid Build Coastguard Worker 
43*25da2beaSAndroid Build Coastguard Worker #define DEFINE_AWAIT_OP(operation) 					\
44*25da2beaSAndroid Build Coastguard Worker static ssize_t await_##operation(					\
45*25da2beaSAndroid Build Coastguard Worker 	async_context *pctx,						\
46*25da2beaSAndroid Build Coastguard Worker 	int fd,								\
47*25da2beaSAndroid Build Coastguard Worker 	const struct iovec *ioves,					\
48*25da2beaSAndroid Build Coastguard Worker 	unsigned int nr_vecs,						\
49*25da2beaSAndroid Build Coastguard Worker 	off_t offset)							\
50*25da2beaSAndroid Build Coastguard Worker {									\
51*25da2beaSAndroid Build Coastguard Worker 	struct io_uring_sqe *sqe = io_uring_get_sqe(pctx->ring);	\
52*25da2beaSAndroid Build Coastguard Worker 	struct io_uring_cqe *cqe;					\
53*25da2beaSAndroid Build Coastguard Worker 									\
54*25da2beaSAndroid Build Coastguard Worker 	if (!sqe)							\
55*25da2beaSAndroid Build Coastguard Worker 		return -1;						\
56*25da2beaSAndroid Build Coastguard Worker 									\
57*25da2beaSAndroid Build Coastguard Worker 	io_uring_prep_##operation(sqe, fd, ioves, nr_vecs, offset);	\
58*25da2beaSAndroid Build Coastguard Worker 	io_uring_sqe_set_data(sqe, pctx);				\
59*25da2beaSAndroid Build Coastguard Worker 	swapcontext(&pctx->ctx_fnew, &pctx->ctx_main);			\
60*25da2beaSAndroid Build Coastguard Worker 	io_uring_peek_cqe(pctx->ring, &cqe);				\
61*25da2beaSAndroid Build Coastguard Worker 	assert(cqe);							\
62*25da2beaSAndroid Build Coastguard Worker 	io_uring_cqe_seen(pctx->ring, cqe);				\
63*25da2beaSAndroid Build Coastguard Worker 									\
64*25da2beaSAndroid Build Coastguard Worker 	return cqe->res;						\
65*25da2beaSAndroid Build Coastguard Worker }
66*25da2beaSAndroid Build Coastguard Worker 
67*25da2beaSAndroid Build Coastguard Worker DEFINE_AWAIT_OP(readv)
DEFINE_AWAIT_OP(writev)68*25da2beaSAndroid Build Coastguard Worker DEFINE_AWAIT_OP(writev)
69*25da2beaSAndroid Build Coastguard Worker #undef DEFINE_AWAIT_OP
70*25da2beaSAndroid Build Coastguard Worker 
71*25da2beaSAndroid Build Coastguard Worker int await_poll(async_context *pctx, int fd, short poll_mask) {
72*25da2beaSAndroid Build Coastguard Worker 	struct io_uring_sqe *sqe = io_uring_get_sqe(pctx->ring);
73*25da2beaSAndroid Build Coastguard Worker 	struct io_uring_cqe *cqe;
74*25da2beaSAndroid Build Coastguard Worker 	if (!sqe)
75*25da2beaSAndroid Build Coastguard Worker 		return -1;
76*25da2beaSAndroid Build Coastguard Worker 
77*25da2beaSAndroid Build Coastguard Worker 	io_uring_prep_poll_add(sqe, fd, poll_mask);
78*25da2beaSAndroid Build Coastguard Worker 	io_uring_sqe_set_data(sqe, pctx);
79*25da2beaSAndroid Build Coastguard Worker 	swapcontext(&pctx->ctx_fnew, &pctx->ctx_main);
80*25da2beaSAndroid Build Coastguard Worker 	io_uring_peek_cqe(pctx->ring, &cqe);
81*25da2beaSAndroid Build Coastguard Worker 	assert(cqe);
82*25da2beaSAndroid Build Coastguard Worker 	io_uring_cqe_seen(pctx->ring, cqe);
83*25da2beaSAndroid Build Coastguard Worker 
84*25da2beaSAndroid Build Coastguard Worker 	return cqe->res;
85*25da2beaSAndroid Build Coastguard Worker }
86*25da2beaSAndroid Build Coastguard Worker 
await_delay(async_context * pctx,time_t seconds)87*25da2beaSAndroid Build Coastguard Worker int await_delay(async_context *pctx, time_t seconds) {
88*25da2beaSAndroid Build Coastguard Worker 	struct io_uring_sqe *sqe = io_uring_get_sqe(pctx->ring);
89*25da2beaSAndroid Build Coastguard Worker 	struct io_uring_cqe *cqe;
90*25da2beaSAndroid Build Coastguard Worker 	struct __kernel_timespec ts = {
91*25da2beaSAndroid Build Coastguard Worker 		.tv_sec = seconds,
92*25da2beaSAndroid Build Coastguard Worker 		.tv_nsec = 0
93*25da2beaSAndroid Build Coastguard Worker 	};
94*25da2beaSAndroid Build Coastguard Worker 
95*25da2beaSAndroid Build Coastguard Worker 	if (!sqe)
96*25da2beaSAndroid Build Coastguard Worker 		return -1;
97*25da2beaSAndroid Build Coastguard Worker 
98*25da2beaSAndroid Build Coastguard Worker 	io_uring_prep_timeout(sqe, &ts, 0, 0);
99*25da2beaSAndroid Build Coastguard Worker 	io_uring_sqe_set_data(sqe, pctx);
100*25da2beaSAndroid Build Coastguard Worker 	swapcontext(&pctx->ctx_fnew, &pctx->ctx_main);
101*25da2beaSAndroid Build Coastguard Worker 	io_uring_peek_cqe(pctx->ring, &cqe);
102*25da2beaSAndroid Build Coastguard Worker 	assert(cqe);
103*25da2beaSAndroid Build Coastguard Worker 	io_uring_cqe_seen(pctx->ring, cqe);
104*25da2beaSAndroid Build Coastguard Worker 
105*25da2beaSAndroid Build Coastguard Worker 	return 0;
106*25da2beaSAndroid Build Coastguard Worker }
107*25da2beaSAndroid Build Coastguard Worker 
setup_context(async_context * pctx,struct io_uring * ring)108*25da2beaSAndroid Build Coastguard Worker static int setup_context(async_context *pctx, struct io_uring *ring)
109*25da2beaSAndroid Build Coastguard Worker {
110*25da2beaSAndroid Build Coastguard Worker 	int ret;
111*25da2beaSAndroid Build Coastguard Worker 
112*25da2beaSAndroid Build Coastguard Worker 	pctx->ring = ring;
113*25da2beaSAndroid Build Coastguard Worker 	ret = getcontext(&pctx->ctx_fnew);
114*25da2beaSAndroid Build Coastguard Worker 	if (ret < 0) {
115*25da2beaSAndroid Build Coastguard Worker 		perror("getcontext");
116*25da2beaSAndroid Build Coastguard Worker 		return -1;
117*25da2beaSAndroid Build Coastguard Worker 	}
118*25da2beaSAndroid Build Coastguard Worker 	pctx->stack_buf = malloc(SIGSTKSZ);
119*25da2beaSAndroid Build Coastguard Worker 	if (!pctx->stack_buf) {
120*25da2beaSAndroid Build Coastguard Worker 		perror("malloc");
121*25da2beaSAndroid Build Coastguard Worker 		return -1;
122*25da2beaSAndroid Build Coastguard Worker 	}
123*25da2beaSAndroid Build Coastguard Worker 	pctx->ctx_fnew.uc_stack.ss_sp = pctx->stack_buf;
124*25da2beaSAndroid Build Coastguard Worker 	pctx->ctx_fnew.uc_stack.ss_size = SIGSTKSZ;
125*25da2beaSAndroid Build Coastguard Worker 	pctx->ctx_fnew.uc_link = &pctx->ctx_main;
126*25da2beaSAndroid Build Coastguard Worker 
127*25da2beaSAndroid Build Coastguard Worker 	return 0;
128*25da2beaSAndroid Build Coastguard Worker }
129*25da2beaSAndroid Build Coastguard Worker 
copy_file(async_context * pctx,int infd,int outfd,struct iovec * piov)130*25da2beaSAndroid Build Coastguard Worker static int copy_file(async_context *pctx, int infd, int outfd, struct iovec* piov)
131*25da2beaSAndroid Build Coastguard Worker {
132*25da2beaSAndroid Build Coastguard Worker 	off_t offset = 0;
133*25da2beaSAndroid Build Coastguard Worker 
134*25da2beaSAndroid Build Coastguard Worker 	for (;;) {
135*25da2beaSAndroid Build Coastguard Worker 		ssize_t bytes_read;
136*25da2beaSAndroid Build Coastguard Worker 
137*25da2beaSAndroid Build Coastguard Worker 		printf("%d->%d: readv %ld bytes from %ld\n", infd, outfd, (long) piov->iov_len, (long) offset);
138*25da2beaSAndroid Build Coastguard Worker 		if ((bytes_read = await_readv(pctx, infd, piov, 1, offset)) < 0) {
139*25da2beaSAndroid Build Coastguard Worker 			perror("await_readv");
140*25da2beaSAndroid Build Coastguard Worker 			return 1;
141*25da2beaSAndroid Build Coastguard Worker 		}
142*25da2beaSAndroid Build Coastguard Worker 		if (bytes_read == 0)
143*25da2beaSAndroid Build Coastguard Worker 			return 0;
144*25da2beaSAndroid Build Coastguard Worker 
145*25da2beaSAndroid Build Coastguard Worker 		piov->iov_len = bytes_read;
146*25da2beaSAndroid Build Coastguard Worker 
147*25da2beaSAndroid Build Coastguard Worker 		printf("%d->%d: writev %ld bytes from %ld\n", infd, outfd, (long) piov->iov_len, (long) offset);
148*25da2beaSAndroid Build Coastguard Worker 		if (await_writev(pctx, outfd, piov, 1, offset) != bytes_read) {
149*25da2beaSAndroid Build Coastguard Worker 			perror("await_writev");
150*25da2beaSAndroid Build Coastguard Worker 			return 1;
151*25da2beaSAndroid Build Coastguard Worker 		}
152*25da2beaSAndroid Build Coastguard Worker 		if (bytes_read < BS)
153*25da2beaSAndroid Build Coastguard Worker 			return 0;
154*25da2beaSAndroid Build Coastguard Worker 		offset += bytes_read;
155*25da2beaSAndroid Build Coastguard Worker 
156*25da2beaSAndroid Build Coastguard Worker 		printf("%d->%d: wait %ds\n", infd, outfd, 1);
157*25da2beaSAndroid Build Coastguard Worker 		await_delay(pctx, 1);
158*25da2beaSAndroid Build Coastguard Worker 	}
159*25da2beaSAndroid Build Coastguard Worker }
160*25da2beaSAndroid Build Coastguard Worker 
copy_file_wrapper(arguments_bundle * pbundle)161*25da2beaSAndroid Build Coastguard Worker static void copy_file_wrapper(arguments_bundle *pbundle)
162*25da2beaSAndroid Build Coastguard Worker {
163*25da2beaSAndroid Build Coastguard Worker 	struct iovec iov = {
164*25da2beaSAndroid Build Coastguard Worker 		.iov_base = malloc(BS),
165*25da2beaSAndroid Build Coastguard Worker 		.iov_len = BS,
166*25da2beaSAndroid Build Coastguard Worker 	};
167*25da2beaSAndroid Build Coastguard Worker 	async_context *pctx = pbundle->pctx;
168*25da2beaSAndroid Build Coastguard Worker 
169*25da2beaSAndroid Build Coastguard Worker 	int ret = copy_file(pctx, pbundle->infd, pbundle->outfd, &iov);
170*25da2beaSAndroid Build Coastguard Worker 
171*25da2beaSAndroid Build Coastguard Worker 	printf("%d->%d: done with ret code %d\n", pbundle->infd, pbundle->outfd, ret);
172*25da2beaSAndroid Build Coastguard Worker 
173*25da2beaSAndroid Build Coastguard Worker 	if (ret == 0) {
174*25da2beaSAndroid Build Coastguard Worker 		++*pbundle->psuccess;
175*25da2beaSAndroid Build Coastguard Worker 	} else {
176*25da2beaSAndroid Build Coastguard Worker 		++*pbundle->pfailure;
177*25da2beaSAndroid Build Coastguard Worker 	}
178*25da2beaSAndroid Build Coastguard Worker 
179*25da2beaSAndroid Build Coastguard Worker 	free(iov.iov_base);
180*25da2beaSAndroid Build Coastguard Worker 	close(pbundle->infd);
181*25da2beaSAndroid Build Coastguard Worker 	close(pbundle->outfd);
182*25da2beaSAndroid Build Coastguard Worker 	free(pbundle->pctx->stack_buf);
183*25da2beaSAndroid Build Coastguard Worker 	free(pbundle->pctx);
184*25da2beaSAndroid Build Coastguard Worker 	free(pbundle);
185*25da2beaSAndroid Build Coastguard Worker 
186*25da2beaSAndroid Build Coastguard Worker 	swapcontext(&pctx->ctx_fnew, &pctx->ctx_main);
187*25da2beaSAndroid Build Coastguard Worker }
188*25da2beaSAndroid Build Coastguard Worker 
main(int argc,char * argv[])189*25da2beaSAndroid Build Coastguard Worker int main(int argc, char *argv[])
190*25da2beaSAndroid Build Coastguard Worker {
191*25da2beaSAndroid Build Coastguard Worker 	struct io_uring ring;
192*25da2beaSAndroid Build Coastguard Worker 	int i, req_count, ret;
193*25da2beaSAndroid Build Coastguard Worker 	int success = 0, failure = 0;
194*25da2beaSAndroid Build Coastguard Worker 
195*25da2beaSAndroid Build Coastguard Worker 	if (argc < 3) {
196*25da2beaSAndroid Build Coastguard Worker 		fprintf(stderr, "%s: infile1 outfile1 [infile2 outfile2 [...]]\n", argv[0]);
197*25da2beaSAndroid Build Coastguard Worker 		return 1;
198*25da2beaSAndroid Build Coastguard Worker 	}
199*25da2beaSAndroid Build Coastguard Worker 
200*25da2beaSAndroid Build Coastguard Worker 	ret = io_uring_queue_init(QD, &ring, 0);
201*25da2beaSAndroid Build Coastguard Worker 	if (ret < 0) {
202*25da2beaSAndroid Build Coastguard Worker 		fprintf(stderr, "queue_init: %s\n", strerror(-ret));
203*25da2beaSAndroid Build Coastguard Worker 		return -1;
204*25da2beaSAndroid Build Coastguard Worker 	}
205*25da2beaSAndroid Build Coastguard Worker 
206*25da2beaSAndroid Build Coastguard Worker 	req_count = (argc - 1) / 2;
207*25da2beaSAndroid Build Coastguard Worker 	printf("copying %d files...\n", req_count);
208*25da2beaSAndroid Build Coastguard Worker 
209*25da2beaSAndroid Build Coastguard Worker 	for (i = 1; i < argc; i += 2) {
210*25da2beaSAndroid Build Coastguard Worker 		int infd, outfd;
211*25da2beaSAndroid Build Coastguard Worker 
212*25da2beaSAndroid Build Coastguard Worker 		async_context *pctx = malloc(sizeof(*pctx));
213*25da2beaSAndroid Build Coastguard Worker 
214*25da2beaSAndroid Build Coastguard Worker 		if (!pctx || setup_context(pctx, &ring))
215*25da2beaSAndroid Build Coastguard Worker 			return 1;
216*25da2beaSAndroid Build Coastguard Worker 
217*25da2beaSAndroid Build Coastguard Worker 		infd = open(argv[i], O_RDONLY);
218*25da2beaSAndroid Build Coastguard Worker 		if (infd < 0) {
219*25da2beaSAndroid Build Coastguard Worker 			perror("open infile");
220*25da2beaSAndroid Build Coastguard Worker 			return 1;
221*25da2beaSAndroid Build Coastguard Worker 		}
222*25da2beaSAndroid Build Coastguard Worker 		outfd = open(argv[i + 1], O_WRONLY | O_CREAT | O_TRUNC, 0644);
223*25da2beaSAndroid Build Coastguard Worker 		if (outfd < 0) {
224*25da2beaSAndroid Build Coastguard Worker 			perror("open outfile");
225*25da2beaSAndroid Build Coastguard Worker 			return 1;
226*25da2beaSAndroid Build Coastguard Worker 		}
227*25da2beaSAndroid Build Coastguard Worker 
228*25da2beaSAndroid Build Coastguard Worker 		arguments_bundle *pbundle = malloc(sizeof(*pbundle));
229*25da2beaSAndroid Build Coastguard Worker 		pbundle->pctx = pctx;
230*25da2beaSAndroid Build Coastguard Worker 		pbundle->psuccess = &success;
231*25da2beaSAndroid Build Coastguard Worker 		pbundle->pfailure = &failure;
232*25da2beaSAndroid Build Coastguard Worker 		pbundle->infd = infd;
233*25da2beaSAndroid Build Coastguard Worker 		pbundle->outfd = outfd;
234*25da2beaSAndroid Build Coastguard Worker 
235*25da2beaSAndroid Build Coastguard Worker 		makecontext(&pctx->ctx_fnew, (void (*)(void)) copy_file_wrapper, 1, pbundle);
236*25da2beaSAndroid Build Coastguard Worker 
237*25da2beaSAndroid Build Coastguard Worker 		if (swapcontext(&pctx->ctx_main, &pctx->ctx_fnew)) {
238*25da2beaSAndroid Build Coastguard Worker 			perror("swapcontext");
239*25da2beaSAndroid Build Coastguard Worker 			return 1;
240*25da2beaSAndroid Build Coastguard Worker 		}
241*25da2beaSAndroid Build Coastguard Worker 	}
242*25da2beaSAndroid Build Coastguard Worker 
243*25da2beaSAndroid Build Coastguard Worker 	/* event loop */
244*25da2beaSAndroid Build Coastguard Worker 	while (success + failure < req_count) {
245*25da2beaSAndroid Build Coastguard Worker 		struct io_uring_cqe *cqe;
246*25da2beaSAndroid Build Coastguard Worker 
247*25da2beaSAndroid Build Coastguard Worker 		/* usually be timed waiting */
248*25da2beaSAndroid Build Coastguard Worker 		ret = io_uring_submit_and_wait(&ring, 1);
249*25da2beaSAndroid Build Coastguard Worker 		if (ret < 0) {
250*25da2beaSAndroid Build Coastguard Worker 			fprintf(stderr, "submit_and_wait: %s\n", strerror(-ret));
251*25da2beaSAndroid Build Coastguard Worker 			return 1;
252*25da2beaSAndroid Build Coastguard Worker 		}
253*25da2beaSAndroid Build Coastguard Worker 
254*25da2beaSAndroid Build Coastguard Worker 		ret = io_uring_wait_cqe(&ring, &cqe);
255*25da2beaSAndroid Build Coastguard Worker 		if (ret < 0) {
256*25da2beaSAndroid Build Coastguard Worker 			fprintf(stderr, "wait_cqe: %s\n", strerror(-ret));
257*25da2beaSAndroid Build Coastguard Worker 			return 1;
258*25da2beaSAndroid Build Coastguard Worker 		}
259*25da2beaSAndroid Build Coastguard Worker 
260*25da2beaSAndroid Build Coastguard Worker 		async_context *pctx = io_uring_cqe_get_data(cqe);
261*25da2beaSAndroid Build Coastguard Worker 
262*25da2beaSAndroid Build Coastguard Worker 		if (swapcontext(&pctx->ctx_main, &pctx->ctx_fnew)) {
263*25da2beaSAndroid Build Coastguard Worker 			perror("swapcontext");
264*25da2beaSAndroid Build Coastguard Worker 			return 1;
265*25da2beaSAndroid Build Coastguard Worker 		}
266*25da2beaSAndroid Build Coastguard Worker 	}
267*25da2beaSAndroid Build Coastguard Worker 
268*25da2beaSAndroid Build Coastguard Worker 	io_uring_queue_exit(&ring);
269*25da2beaSAndroid Build Coastguard Worker 
270*25da2beaSAndroid Build Coastguard Worker 	printf("finished with %d success(es) and %d failure(s)\n", success, failure);
271*25da2beaSAndroid Build Coastguard Worker 
272*25da2beaSAndroid Build Coastguard Worker 	return failure > 0;
273*25da2beaSAndroid Build Coastguard Worker }
274