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