xref: /openbsd/regress/sys/kern/pipe/test-kqueue.c (revision fc11865a)
1*fc11865aSanton /*	$OpenBSD: test-kqueue.c,v 1.3 2021/05/08 06:53:19 anton Exp $	*/
2e22febffSanton 
3e22febffSanton /*
4e22febffSanton  * Copyright (c) 2019 Anton Lindqvist <anton@openbsd.org>
5e22febffSanton  *
6e22febffSanton  * Permission to use, copy, modify, and distribute this software for any
7e22febffSanton  * purpose with or without fee is hereby granted, provided that the above
8e22febffSanton  * copyright notice and this permission notice appear in all copies.
9e22febffSanton  *
10e22febffSanton  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11e22febffSanton  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12e22febffSanton  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13e22febffSanton  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14e22febffSanton  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15e22febffSanton  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16e22febffSanton  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17e22febffSanton  */
18e22febffSanton 
19e22febffSanton #include <sys/types.h>
20e22febffSanton #include <sys/event.h>
21e22febffSanton #include <sys/time.h>
22e22febffSanton 
23e22febffSanton #include <err.h>
24*fc11865aSanton #include <errno.h>
25*fc11865aSanton #include <fcntl.h>
26e22febffSanton #include <pthread.h>
27e22febffSanton #include <stdlib.h>
28e22febffSanton #include <unistd.h>
29e22febffSanton 
30e22febffSanton #include "pipe.h"
31e22febffSanton 
32e22febffSanton enum kqueue_mode {
33e22febffSanton 	KQUEUE_READ,
34e22febffSanton 	KQUEUE_READ_EOF,
35e22febffSanton 	KQUEUE_WRITE,
36e22febffSanton 	KQUEUE_WRITE_EOF,
37e22febffSanton };
38e22febffSanton 
39e22febffSanton struct context {
40e22febffSanton 	enum kqueue_mode c_mode;
41e22febffSanton 	int c_alive;
42e22febffSanton 
43e22febffSanton 	int c_pipe[2];
44e22febffSanton 	int c_kq;
45e22febffSanton 
46e22febffSanton 	char *c_buf;
47e22febffSanton 	size_t c_bufsiz;
48e22febffSanton 
49e22febffSanton 	pthread_t c_th;
50e22febffSanton 	pthread_mutex_t c_mtx;
51e22febffSanton };
52e22febffSanton 
53*fc11865aSanton static void ctx_setup(struct context *, enum kqueue_mode, int);
54e22febffSanton static void ctx_teardown(struct context *);
55e22febffSanton static int ctx_thread_alive(struct context *);
56e22febffSanton static void ctx_thread_start(struct context *);
57e22febffSanton static void ctx_lock(struct context *);
58e22febffSanton static void ctx_unlock(struct context *);
59e22febffSanton 
60e22febffSanton static void *kqueue_thread(void *);
61e22febffSanton 
62e22febffSanton /*
63e22febffSanton  * Verify kqueue read event.
64e22febffSanton  */
65e22febffSanton int
66e22febffSanton test_kqueue_read(void)
67e22febffSanton {
68e22febffSanton 	struct context ctx;
69e22febffSanton 
70*fc11865aSanton 	ctx_setup(&ctx, KQUEUE_READ, O_NONBLOCK);
71e22febffSanton 	ctx_thread_start(&ctx);
72e22febffSanton 
73e22febffSanton 	while (ctx_thread_alive(&ctx)) {
74e22febffSanton 		ssize_t n;
75e22febffSanton 
76*fc11865aSanton 		n = write(ctx.c_pipe[1], &ctx.c_buf[0], 1);
77*fc11865aSanton 		if (n == -1) {
78*fc11865aSanton 			if (errno == EAGAIN)
79*fc11865aSanton 				continue;
80e22febffSanton 			err(1, "write");
81*fc11865aSanton 		}
82e22febffSanton 		if (n != 1)
83e22febffSanton 			errx(1, "write: %ld != 1", n);
84e22febffSanton 	}
85e22febffSanton 
86e22febffSanton 	ctx_teardown(&ctx);
87e22febffSanton 
88e22febffSanton 	return 0;
89e22febffSanton }
90e22febffSanton 
91e22febffSanton /*
92e22febffSanton  * Verify kqueue read EOF event.
93e22febffSanton  */
94e22febffSanton int
95e22febffSanton test_kqueue_read_eof(void)
96e22febffSanton {
97e22febffSanton 	struct context ctx;
98e22febffSanton 
99*fc11865aSanton 	ctx_setup(&ctx, KQUEUE_READ_EOF, 0);
100e22febffSanton 	ctx_thread_start(&ctx);
101e22febffSanton 
102e22febffSanton 	while (ctx_thread_alive(&ctx)) {
103e22febffSanton 		if (ctx.c_pipe[1] == -1)
104e22febffSanton 			continue;
105e22febffSanton 
106e22febffSanton 		close(ctx.c_pipe[1]);
107e22febffSanton 		ctx.c_pipe[1] = -1;
108e22febffSanton 	}
109e22febffSanton 
110e22febffSanton 	ctx_teardown(&ctx);
111e22febffSanton 
112e22febffSanton 	return 0;
113e22febffSanton }
114e22febffSanton 
115e22febffSanton /*
116e22febffSanton  * Verify kqueue write event.
117e22febffSanton  */
118e22febffSanton int
119e22febffSanton test_kqueue_write(void)
120e22febffSanton {
121e22febffSanton 	struct context ctx;
122e22febffSanton 	ssize_t n;
123e22febffSanton 
124*fc11865aSanton 	ctx_setup(&ctx, KQUEUE_WRITE, 0);
125e22febffSanton 
126e22febffSanton 	n = write(ctx.c_pipe[1], ctx.c_buf, ctx.c_bufsiz);
127e22febffSanton 	if (n == -1)
128e22febffSanton 		err(1, "write");
129e22febffSanton 	if ((size_t)n != ctx.c_bufsiz)
130e22febffSanton 		errx(1, "write: %ld != %zu", n, ctx.c_bufsiz);
131e22febffSanton 
132e22febffSanton 	ctx_thread_start(&ctx);
133e22febffSanton 
134e22febffSanton 	while (ctx_thread_alive(&ctx)) {
135e22febffSanton 		unsigned char c;
136e22febffSanton 
137e22febffSanton 		n = read(ctx.c_pipe[0], &c, 1);
138e22febffSanton 		if (n == -1)
139e22febffSanton 			err(1, "read");
140e22febffSanton 		if (n != 1)
141e22febffSanton 			errx(1, "read: %ld != 1", n);
142e22febffSanton 	}
143e22febffSanton 
144e22febffSanton 	ctx_teardown(&ctx);
145e22febffSanton 
146e22febffSanton 	return 0;
147e22febffSanton }
148e22febffSanton 
149e22febffSanton /*
150e22febffSanton  * XXX Verify kqueue write event.
151e22febffSanton  */
152e22febffSanton int
153e22febffSanton test_kqueue_write_eof(void)
154e22febffSanton {
155e22febffSanton 
156e22febffSanton 	return 0;
157e22febffSanton }
158e22febffSanton 
159e22febffSanton static void
160*fc11865aSanton ctx_setup(struct context *ctx, enum kqueue_mode mode, int flags)
161e22febffSanton {
162e22febffSanton 	int error;
163e22febffSanton 
164e22febffSanton 	ctx->c_mode = mode;
165e22febffSanton 	ctx->c_alive = 1;
166e22febffSanton 
167*fc11865aSanton 	if (flags) {
168*fc11865aSanton 		if (pipe2(ctx->c_pipe, flags) == -1)
169*fc11865aSanton 			err(1, "pipe");
170*fc11865aSanton 	} else {
171e22febffSanton 		if (pipe(ctx->c_pipe) == -1)
172e22febffSanton 			err(1, "pipe");
173*fc11865aSanton 	}
174e22febffSanton 
175e22febffSanton 	ctx->c_kq = kqueue();
176e22febffSanton 	if (ctx->c_kq == -1)
177e22febffSanton 		err(1, "kqueue");
178e22febffSanton 
179e22febffSanton 	ctx->c_bufsiz = PIPE_SIZE;
180e22febffSanton 	ctx->c_buf = malloc(ctx->c_bufsiz);
181e22febffSanton 	if (ctx->c_buf == NULL)
182e22febffSanton 		err(1, NULL);
183e22febffSanton 
184e22febffSanton 	error = pthread_mutex_init(&ctx->c_mtx, NULL);
185e22febffSanton 	if (error)
186e22febffSanton 		errc(1, error, "pthread_mutex_init");
187e22febffSanton }
188e22febffSanton 
189e22febffSanton static void
190e22febffSanton ctx_teardown(struct context *ctx)
191e22febffSanton {
192e22febffSanton 	int error;
193e22febffSanton 
194e22febffSanton 	error = pthread_join(ctx->c_th, NULL);
195e22febffSanton 	if (error)
196e22febffSanton 		errc(1, error, "pthread_join");
197e22febffSanton 
198e22febffSanton 	error = pthread_mutex_destroy(&ctx->c_mtx);
199e22febffSanton 	if (error)
200e22febffSanton 		errc(1, error, "pthread_mutex_destroy");
201e22febffSanton 
202e22febffSanton 	free(ctx->c_buf);
203e22febffSanton 
204e22febffSanton 	close(ctx->c_pipe[0]);
205e22febffSanton 	close(ctx->c_pipe[1]);
206e22febffSanton 	close(ctx->c_kq);
207e22febffSanton 
208e22febffSanton }
209e22febffSanton 
210e22febffSanton static int
211e22febffSanton ctx_thread_alive(struct context *ctx)
212e22febffSanton {
213e22febffSanton 	int alive;
214e22febffSanton 
215e22febffSanton 	ctx_lock(ctx);
216e22febffSanton 	alive = ctx->c_alive;
217e22febffSanton 	ctx_unlock(ctx);
218e22febffSanton 	return alive;
219e22febffSanton }
220e22febffSanton 
221e22febffSanton static void
222e22febffSanton ctx_thread_start(struct context *ctx)
223e22febffSanton {
224e22febffSanton 	int error;
225e22febffSanton 
226e22febffSanton 	error = pthread_create(&ctx->c_th, NULL, kqueue_thread, ctx);
227e22febffSanton 	if (error)
228e22febffSanton 		errc(1, error, "pthread_create");
229e22febffSanton }
230e22febffSanton 
231e22febffSanton static void
232e22febffSanton ctx_lock(struct context *ctx)
233e22febffSanton {
234e22febffSanton 	int error;
235e22febffSanton 
236e22febffSanton 	error = pthread_mutex_lock(&ctx->c_mtx);
237e22febffSanton 	if (error)
238e22febffSanton 		errc(1, error, "pthread_mutex_lock");
239e22febffSanton }
240e22febffSanton 
241e22febffSanton static void ctx_unlock(struct context *ctx)
242e22febffSanton {
243e22febffSanton 	int error;
244e22febffSanton 
245e22febffSanton 	error = pthread_mutex_unlock(&ctx->c_mtx);
246e22febffSanton 	if (error)
247e22febffSanton 		errc(1, error, "pthread_mutex_unlock");
248e22febffSanton }
249e22febffSanton 
250e22febffSanton static void *
251e22febffSanton kqueue_thread(void *arg)
252e22febffSanton {
253e22febffSanton 	struct context *ctx = arg;
254e22febffSanton 	struct kevent kev;
255e22febffSanton 	int fd, filter, nevents;
256e22febffSanton 
257e22febffSanton 	switch (ctx->c_mode) {
258e22febffSanton 	case KQUEUE_READ:
259e22febffSanton 	case KQUEUE_READ_EOF:
260e22febffSanton 		fd = ctx->c_pipe[0];
261e22febffSanton 		filter = EVFILT_READ;
262e22febffSanton 		break;
263e22febffSanton 	case KQUEUE_WRITE:
264e22febffSanton 	case KQUEUE_WRITE_EOF:
265e22febffSanton 		fd = ctx->c_pipe[1];
266e22febffSanton 		filter = EVFILT_WRITE;
267e22febffSanton 		break;
268e22febffSanton 	}
269e22febffSanton 
270e22febffSanton 	EV_SET(&kev, fd, filter, EV_ADD, 0, 0, NULL);
271e22febffSanton 	nevents = kevent(ctx->c_kq, &kev, 1, NULL, 0, NULL);
272e22febffSanton 	if (nevents == -1)
273e22febffSanton 		err(1, "kevent");
274e22febffSanton 	nevents = kevent(ctx->c_kq, NULL, 0, &kev, 1, NULL);
275e22febffSanton 	if (nevents == -1)
276e22febffSanton 		err(1, "kevent");
277e22febffSanton 	if (nevents != 1)
278e22febffSanton 		errx(1, "kevent: %d != 1", nevents);
279e22febffSanton 
280cfefc492Santon 	if ((int)kev.ident != fd)
281e22febffSanton 		errx(1, "kevent: ident");
282cfefc492Santon 	if (kev.filter != filter)
283e22febffSanton 		errx(1, "kevent: filter");
284e22febffSanton 
285e22febffSanton 	switch (ctx->c_mode) {
286e22febffSanton 	case KQUEUE_READ_EOF:
287e22febffSanton 	case KQUEUE_WRITE_EOF:
288e22febffSanton 		if ((kev.flags & EV_EOF) == 0)
289e22febffSanton 			errx(1, "kevent: eof");
290e22febffSanton 		break;
291e22febffSanton 	default:
292e22febffSanton 		break;
293e22febffSanton 	}
294e22febffSanton 
295e22febffSanton 	ctx_lock(ctx);
296e22febffSanton 	ctx->c_alive = 0;
297e22febffSanton 	ctx_unlock(ctx);
298e22febffSanton 
299e22febffSanton 	return NULL;
300e22febffSanton }
301