• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: MIT */
2 /*
3  * Description: check that STDOUT write works
4  */
5 #include <errno.h>
6 #include <stdio.h>
7 #include <unistd.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <fcntl.h>
11 
12 #include "helpers.h"
13 #include "liburing.h"
14 
test_pipe_io_fixed(struct io_uring * ring)15 static int test_pipe_io_fixed(struct io_uring *ring)
16 {
17 	const char str[] = "This is a fixed pipe test\n";
18 	struct io_uring_cqe *cqe;
19 	struct io_uring_sqe *sqe;
20 	struct iovec vecs[2];
21 	char buffer[128];
22 	int i, ret, fds[2];
23 
24 	t_posix_memalign(&vecs[0].iov_base, 4096, 4096);
25 	memcpy(vecs[0].iov_base, str, strlen(str));
26 	vecs[0].iov_len = strlen(str);
27 
28 	if (pipe(fds) < 0) {
29 		perror("pipe");
30 		return 1;
31 	}
32 
33 	ret = io_uring_register_buffers(ring, vecs, 1);
34 	if (ret) {
35 		fprintf(stderr, "Failed to register buffers: %d\n", ret);
36 		return 1;
37 	}
38 
39 	sqe = io_uring_get_sqe(ring);
40 	if (!sqe) {
41 		fprintf(stderr, "get sqe failed\n");
42 		goto err;
43 	}
44 	io_uring_prep_write_fixed(sqe, fds[1], vecs[0].iov_base,
45 					vecs[0].iov_len, 0, 0);
46 	sqe->user_data = 1;
47 
48 	sqe = io_uring_get_sqe(ring);
49 	if (!sqe) {
50 		fprintf(stderr, "get sqe failed\n");
51 		goto err;
52 	}
53 	vecs[1].iov_base = buffer;
54 	vecs[1].iov_len = sizeof(buffer);
55 	io_uring_prep_readv(sqe, fds[0], &vecs[1], 1, 0);
56 	sqe->user_data = 2;
57 
58 	ret = io_uring_submit(ring);
59 	if (ret < 0) {
60 		fprintf(stderr, "sqe submit failed: %d\n", ret);
61 		goto err;
62 	} else if (ret != 2) {
63 		fprintf(stderr, "Submitted only %d\n", ret);
64 		goto err;
65 	}
66 
67 	for (i = 0; i < 2; i++) {
68 		ret = io_uring_wait_cqe(ring, &cqe);
69 		if (ret < 0) {
70 			fprintf(stderr, "wait completion %d\n", ret);
71 			goto err;
72 		}
73 		if (cqe->res < 0) {
74 			fprintf(stderr, "I/O write error on %lu: %s\n",
75 					(unsigned long) cqe->user_data,
76 					 strerror(-cqe->res));
77 			goto err;
78 		}
79 		if (cqe->res != strlen(str)) {
80 			fprintf(stderr, "Got %d bytes, wanted %d on %lu\n",
81 					cqe->res, (int)strlen(str),
82 					(unsigned long) cqe->user_data);
83 			goto err;
84 		}
85 		if (cqe->user_data == 2 && memcmp(str, buffer, strlen(str))) {
86 			fprintf(stderr, "read data mismatch\n");
87 			goto err;
88 		}
89 		io_uring_cqe_seen(ring, cqe);
90 	}
91 	io_uring_unregister_buffers(ring);
92 	free(vecs[0].iov_base);
93 	return 0;
94 err:
95 	return 1;
96 }
97 
test_stdout_io_fixed(struct io_uring * ring)98 static int test_stdout_io_fixed(struct io_uring *ring)
99 {
100 	const char str[] = "This is a fixed pipe test\n";
101 	struct io_uring_cqe *cqe;
102 	struct io_uring_sqe *sqe;
103 	struct iovec vecs;
104 	int ret;
105 
106 	t_posix_memalign(&vecs.iov_base, 4096, 4096);
107 	memcpy(vecs.iov_base, str, strlen(str));
108 	vecs.iov_len = strlen(str);
109 
110 	ret = io_uring_register_buffers(ring, &vecs, 1);
111 	if (ret) {
112 		fprintf(stderr, "Failed to register buffers: %d\n", ret);
113 		return 1;
114 	}
115 
116 	sqe = io_uring_get_sqe(ring);
117 	if (!sqe) {
118 		fprintf(stderr, "get sqe failed\n");
119 		goto err;
120 	}
121 	io_uring_prep_write_fixed(sqe, STDOUT_FILENO, vecs.iov_base, vecs.iov_len, 0, 0);
122 
123 	ret = io_uring_submit(ring);
124 	if (ret < 0) {
125 		fprintf(stderr, "sqe submit failed: %d\n", ret);
126 		goto err;
127 	} else if (ret < 1) {
128 		fprintf(stderr, "Submitted only %d\n", ret);
129 		goto err;
130 	}
131 
132 	ret = io_uring_wait_cqe(ring, &cqe);
133 	if (ret < 0) {
134 		fprintf(stderr, "wait completion %d\n", ret);
135 		goto err;
136 	}
137 	if (cqe->res < 0) {
138 		fprintf(stderr, "STDOUT write error: %s\n", strerror(-cqe->res));
139 		goto err;
140 	}
141 	if (cqe->res != vecs.iov_len) {
142 		fprintf(stderr, "Got %d write, wanted %d\n", cqe->res, (int)vecs.iov_len);
143 		goto err;
144 	}
145 	io_uring_cqe_seen(ring, cqe);
146 	io_uring_unregister_buffers(ring);
147 	free(vecs.iov_base);
148 	return 0;
149 err:
150 	return 1;
151 }
152 
test_stdout_io(struct io_uring * ring)153 static int test_stdout_io(struct io_uring *ring)
154 {
155 	struct io_uring_cqe *cqe;
156 	struct io_uring_sqe *sqe;
157 	struct iovec vecs;
158 	int ret;
159 
160 	vecs.iov_base = "This is a pipe test\n";
161 	vecs.iov_len = strlen(vecs.iov_base);
162 
163 	sqe = io_uring_get_sqe(ring);
164 	if (!sqe) {
165 		fprintf(stderr, "get sqe failed\n");
166 		goto err;
167 	}
168 	io_uring_prep_writev(sqe, STDOUT_FILENO, &vecs, 1, 0);
169 
170 	ret = io_uring_submit(ring);
171 	if (ret < 0) {
172 		fprintf(stderr, "sqe submit failed: %d\n", ret);
173 		goto err;
174 	} else if (ret < 1) {
175 		fprintf(stderr, "Submitted only %d\n", ret);
176 		goto err;
177 	}
178 
179 	ret = io_uring_wait_cqe(ring, &cqe);
180 	if (ret < 0) {
181 		fprintf(stderr, "wait completion %d\n", ret);
182 		goto err;
183 	}
184 	if (cqe->res < 0) {
185 		fprintf(stderr, "STDOUT write error: %s\n",
186 				strerror(-cqe->res));
187 		goto err;
188 	}
189 	if (cqe->res != vecs.iov_len) {
190 		fprintf(stderr, "Got %d write, wanted %d\n", cqe->res,
191 				(int)vecs.iov_len);
192 		goto err;
193 	}
194 	io_uring_cqe_seen(ring, cqe);
195 
196 	return 0;
197 err:
198 	return 1;
199 }
200 
main(int argc,char * argv[])201 int main(int argc, char *argv[])
202 {
203 	struct io_uring ring;
204 	int ret;
205 
206 	if (argc > 1)
207 		return 0;
208 
209 	ret = io_uring_queue_init(8, &ring, 0);
210 	if (ret) {
211 		fprintf(stderr, "ring setup failed\n");
212 		return 1;
213 	}
214 
215 	ret = test_stdout_io(&ring);
216 	if (ret) {
217 		fprintf(stderr, "test_pipe_io failed\n");
218 		return ret;
219 	}
220 
221 	ret = test_stdout_io_fixed(&ring);
222 	if (ret) {
223 		fprintf(stderr, "test_pipe_io_fixed failed\n");
224 		return ret;
225 	}
226 
227 	ret = test_pipe_io_fixed(&ring);
228 	if (ret) {
229 		fprintf(stderr, "test_pipe_io_fixed failed\n");
230 		return ret;
231 	}
232 
233 	return 0;
234 }
235