On Sun, Aug 13, 2023 at 05:58:01PM -0700, Philip Guenther wrote: > I think that changing the behavior of the existing API in a way that > gratuitously increases the differences between BSDs is unwise. IMHO, we > should follow NetBSD on this and add kqueue1(), that being obviously > consistent with the previous 'add flags argument' extensions: pipe2(), > dup3(), and accept4().
I agree that changing the behavior is not good. Below is an implementation of the kqueue1() syscall and the libc stub. NetBSD's kqueue1() accepts flags that do not really affect kqueue behavior, namely O_NONBLOCK and O_NOSIGPIPE (this is specific to NetBSD). For compatibility, the new syscall code passes O_NONBLOCK to file flags but otherwise ignores it. I have omitted this flag from the syscall manual page because it does not make sense with kqueue. However, I can add a note about the flag if it is deemed necessary. Index: sys/kern/kern_event.c =================================================================== RCS file: src/sys/kern/kern_event.c,v retrieving revision 1.197 diff -u -p -r1.197 kern_event.c --- sys/kern/kern_event.c 13 Aug 2023 08:29:28 -0000 1.197 +++ sys/kern/kern_event.c 14 Aug 2023 14:52:44 -0000 @@ -60,6 +60,7 @@ #define KLIST_ASSERT_LOCKED(kl) ((void)(kl)) #endif +int dokqueue(struct proc *, int, register_t *); struct kqueue *kqueue_alloc(struct filedesc *); void kqueue_terminate(struct proc *p, struct kqueue *); void KQREF(struct kqueue *); @@ -912,12 +913,14 @@ kqueue_alloc(struct filedesc *fdp) } int -sys_kqueue(struct proc *p, void *v, register_t *retval) +dokqueue(struct proc *p, int flags, register_t *retval) { struct filedesc *fdp = p->p_fd; struct kqueue *kq; struct file *fp; - int fd, error; + int cloexec, error, fd; + + cloexec = (flags & O_CLOEXEC) ? UF_EXCLOSE : 0; kq = kqueue_alloc(fdp); @@ -925,14 +928,14 @@ sys_kqueue(struct proc *p, void *v, regi error = falloc(p, &fp, &fd); if (error) goto out; - fp->f_flag = FREAD | FWRITE; + fp->f_flag = FREAD | FWRITE | (flags & FNONBLOCK); fp->f_type = DTYPE_KQUEUE; fp->f_ops = &kqueueops; fp->f_data = kq; *retval = fd; LIST_INSERT_HEAD(&fdp->fd_kqlist, kq, kq_next); kq = NULL; - fdinsert(fdp, fd, 0, fp); + fdinsert(fdp, fd, cloexec, fp); FRELE(fp, p); out: fdpunlock(fdp); @@ -942,6 +945,24 @@ out: } int +sys_kqueue(struct proc *p, void *v, register_t *retval) +{ + return (dokqueue(p, 0, retval)); +} + +int +sys_kqueue1(struct proc *p, void *v, register_t *retval) +{ + struct sys_kqueue1_args /* { + syscallarg(int) flags; + } */ *uap = v; + + if (SCARG(uap, flags) & ~(O_CLOEXEC | O_NONBLOCK)) + return (EINVAL); + return (dokqueue(p, SCARG(uap, flags), retval)); +} + +int sys_kevent(struct proc *p, void *v, register_t *retval) { struct kqueue_scan_state scan; Index: sys/kern/syscalls.master =================================================================== RCS file: src/sys/kern/syscalls.master,v retrieving revision 1.249 diff -u -p -r1.249 syscalls.master --- sys/kern/syscalls.master 24 Jul 2023 19:32:23 -0000 1.249 +++ sys/kern/syscalls.master 14 Aug 2023 14:52:44 -0000 @@ -462,7 +462,7 @@ 267 OBSOL pad_preadv 268 OBSOL pad_pwritev 269 STD NOLOCK { int sys_kqueue(void); } -270 OBSOL t32_kevent +270 STD NOLOCK { int sys_kqueue1(int flags); } 271 STD { int sys_mlockall(int flags); } 272 STD { int sys_munlockall(void); } 273 UNIMPL sys_getpeereid Index: sys/sys/event.h =================================================================== RCS file: src/sys/sys/event.h,v retrieving revision 1.70 diff -u -p -r1.70 event.h --- sys/sys/event.h 13 Aug 2023 08:29:28 -0000 1.70 +++ sys/sys/event.h 14 Aug 2023 14:52:44 -0000 @@ -369,6 +369,7 @@ struct timespec; __BEGIN_DECLS int kqueue(void); +int kqueue1(int flags); int kevent(int kq, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout); Index: lib/libc/Symbols.list =================================================================== RCS file: src/lib/libc/Symbols.list,v retrieving revision 1.81 diff -u -p -r1.81 Symbols.list --- lib/libc/Symbols.list 11 Feb 2023 23:07:28 -0000 1.81 +++ lib/libc/Symbols.list 14 Aug 2023 14:52:42 -0000 @@ -121,6 +121,7 @@ _thread_sys_issetugid _thread_sys_kevent _thread_sys_kill _thread_sys_kqueue +_thread_sys_kqueue1 _thread_sys_ktrace _thread_sys_lchown _thread_sys_link @@ -322,6 +323,7 @@ issetugid kevent kill kqueue +kqueue1 ktrace lchown link Index: lib/libc/shlib_version =================================================================== RCS file: src/lib/libc/shlib_version,v retrieving revision 1.215 diff -u -p -r1.215 shlib_version --- lib/libc/shlib_version 11 Feb 2023 23:07:51 -0000 1.215 +++ lib/libc/shlib_version 14 Aug 2023 14:52:42 -0000 @@ -1,4 +1,4 @@ major=97 -minor=0 +minor=1 # note: If changes were made to include/thread_private.h or if system calls # were added/changed then librthread/shlib_version must also be updated. Index: lib/libc/hidden/sys/event.h =================================================================== RCS file: src/lib/libc/hidden/sys/event.h,v retrieving revision 1.1 diff -u -p -r1.1 event.h --- lib/libc/hidden/sys/event.h 18 May 2023 16:11:09 -0000 1.1 +++ lib/libc/hidden/sys/event.h 14 Aug 2023 14:52:42 -0000 @@ -22,5 +22,6 @@ PROTO_NORMAL(kevent); PROTO_NORMAL(kqueue); +PROTO_NORMAL(kqueue1); #endif /* !_LIBC_SYS_EVENT_H_ */ Index: lib/libc/sys/Makefile.inc =================================================================== RCS file: src/lib/libc/sys/Makefile.inc,v retrieving revision 1.173 diff -u -p -r1.173 Makefile.inc --- lib/libc/sys/Makefile.inc 27 Feb 2023 14:59:33 -0000 1.173 +++ lib/libc/sys/Makefile.inc 14 Aug 2023 14:52:42 -0000 @@ -73,7 +73,7 @@ ASM= __semctl.o __thrsigdivert.o \ getpriority.o getresgid.o getresuid.o \ getrlimit.o getrusage.o getsid.o getsockname.o \ getsockopt.o ioctl.o \ - kevent.o kill.o kqueue.o ktrace.o lchown.o \ + kevent.o kill.o kqueue.o kqueue1.o ktrace.o lchown.o \ link.o linkat.o listen.o lseek.o lstat.o \ madvise.o mimmutable.o minherit.o mkdir.o mkdirat.o mkfifo.o mkfifoat.o \ mknod.o mknodat.o mlock.o mlockall.o mmap.o mount.o mprotect.o \ Index: lib/libc/sys/kqueue.2 =================================================================== RCS file: src/lib/libc/sys/kqueue.2,v retrieving revision 1.49 diff -u -p -r1.49 kqueue.2 --- lib/libc/sys/kqueue.2 13 Aug 2023 10:23:26 -0000 1.49 +++ lib/libc/sys/kqueue.2 14 Aug 2023 14:52:42 -0000 @@ -31,6 +31,7 @@ .Os .Sh NAME .Nm kqueue , +.Nm kqueue1 , .Nm kevent , .Nm EV_SET .Nd kernel event notification mechanism @@ -43,6 +44,12 @@ .Ft int .Fn kevent "int kq" "const struct kevent *changelist" "int nchanges" "struct kevent *eventlist" "int nevents" "const struct timespec *timeout" .Fn EV_SET "&kev" ident filter flags fflags data udata +.In sys/types.h +.In sys/event.h +.In sys/time.h +.In fcntl.h +.Ft int +.Fn kqueue1 "int flags" .Sh DESCRIPTION .Fn kqueue provides a generic method of notifying the user when an event @@ -78,6 +85,15 @@ The queue is not inherited by a child cr .Xr fork 2 . Similarly, kqueues cannot be passed across UNIX-domain sockets. .Pp +.Fn kqueue1 +is similar to +.Fn kqueue +but additionally enables the close-on-exec flag on the decriptor +if the +.Dv O_CLOEXEC +bit is set in +.Fa flags . +.Pp .Fn kevent is used to register events with the queue, and return any pending events to the user. @@ -545,7 +561,9 @@ contains the events which triggered the .El .Sh RETURN VALUES .Fn kqueue -creates a new kernel event queue and returns a file descriptor. +and +.Fn kqueue1 +create a new kernel event queue and returns a file descriptor. If there was an error creating the kernel event queue, a value of -1 is returned and .Va errno @@ -577,7 +595,9 @@ returns 0. .Sh ERRORS The .Fn kqueue -function fails if: +and +.Fn kqueue1 +functions fail if: .Bl -tag -width Er .It Bq Er ENOMEM The kernel failed to allocate enough memory for the kernel queue. @@ -587,6 +607,15 @@ The per-process descriptor table is full The system file table is full. .El .Pp +In addition, +.Fn kqueue1 +fails if: +.Bl -tag -width Er +.It Bq Er EINVAL +.Fa flags +is invalid. +.El +.Pp The .Fn kevent function fails if: Index: lib/librthread/shlib_version =================================================================== RCS file: src/lib/librthread/shlib_version,v retrieving revision 1.33 diff -u -p -r1.33 shlib_version --- lib/librthread/shlib_version 12 Feb 2023 17:41:46 -0000 1.33 +++ lib/librthread/shlib_version 14 Aug 2023 14:52:42 -0000 @@ -1,2 +1,2 @@ major=27 -minor=0 +minor=1 Index: regress/sys/kern/kqueue/Makefile =================================================================== RCS file: src/regress/sys/kern/kqueue/Makefile,v retrieving revision 1.31 diff -u -p -r1.31 Makefile --- regress/sys/kern/kqueue/Makefile 30 Mar 2022 05:11:52 -0000 1.31 +++ regress/sys/kern/kqueue/Makefile 14 Aug 2023 14:52:43 -0000 @@ -4,10 +4,12 @@ PROG= kqueue-test CFLAGS+=-Wall SRCS= kqueue-pipe.c kqueue-fork.c main.c kqueue-process.c kqueue-random.c \ kqueue-pty.c kqueue-tun.c kqueue-signal.c kqueue-fdpass.c \ - kqueue-flock.c kqueue-timer.c kqueue-regress.c + kqueue-exec.c kqueue-flock.c kqueue-timer.c kqueue-regress.c LDADD= -levent -lutil DPADD= ${LIBEVENT} ${LIBUTIL} +kq-exec: ${PROG} + ./${PROG} -e kq-pipe: ${PROG} ./${PROG} -p kq-fork: ${PROG} @@ -51,6 +53,7 @@ kq-regress-5: ${PROG} kq-regress-6: ${PROG} ./${PROG} -R6 +TESTS+= kq-exec TESTS+= kq-fdpass TESTS+= kq-flock TESTS+= kq-fork Index: regress/sys/kern/kqueue/kqueue-exec.c =================================================================== RCS file: regress/sys/kern/kqueue/kqueue-exec.c diff -N regress/sys/kern/kqueue/kqueue-exec.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ regress/sys/kern/kqueue/kqueue-exec.c 14 Aug 2023 14:52:43 -0000 @@ -0,0 +1,113 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2023 Visa Hankala + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/event.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "main.h" + +static void do_exec_child(void); +static void do_exec_parent(const char *, int); + +int +do_exec(const char *argv0) +{ + do_exec_parent(argv0, 0); + do_exec_parent(argv0, 1); + return 0; +} + +static void +do_exec_parent(const char *argv0, int cloexec) +{ + char *args[] = { + (char *)argv0, + "-e", + NULL + }; + char fdbuf[12]; + pid_t pid; + int kq, status; + + if (getenv("REGRESS_KQUEUE_FD") != NULL) { + do_exec_child(); + _exit(0); + } + + pid = fork(); + if (pid == -1) + err(1, "fork"); + if (pid == 0) { + kq = kqueue1(cloexec ? O_CLOEXEC : 0); + if (kq == -1) + err(1, "kqueue1"); + snprintf(fdbuf, sizeof(fdbuf), "%d", kq); + if (setenv("REGRESS_KQUEUE_FD", fdbuf, 1) == -1) + err(1, "setenv"); + if (setenv("REGRESS_KQUEUE_CLOEXEC", + cloexec ? "1" : "0", 1) == -1) + err(1, "setenv 2"); + execv(argv0, args); + err(1, "execve"); + } + if (waitpid(pid, &status, 0) == -1) + err(1, "waitpid"); + if (status != 0) + errx(1, "child failed"); +} + +static void +do_exec_child(void) +{ + char *arg; + int cloexec, fd; + + arg = getenv("REGRESS_KQUEUE_FD"); + if (arg == NULL) + errx(1, "fd arg is missing"); + fd = atoi(arg); + + arg = getenv("REGRESS_KQUEUE_CLOEXEC"); + if (arg != NULL && strcmp(arg, "1") == 0) + cloexec = 1; + else + cloexec = 0; + + if (cloexec) { + if (kevent(fd, NULL, 0, NULL, 0, 0) == -1) { + if (errno != EBADF) + err(1, "child after exec: kevent cloexec"); + } else { + errx(1, "child after exec: " + "kqueue cloexec fd is not closed"); + } + } else { + if (kevent(fd, NULL, 0, NULL, 0, 0) == -1) { + err(1, "child after exec: kevent"); + } + } +} Index: regress/sys/kern/kqueue/main.c =================================================================== RCS file: src/regress/sys/kern/kqueue/main.c,v retrieving revision 1.15 diff -u -p -r1.15 main.c --- regress/sys/kern/kqueue/main.c 12 Jun 2021 13:30:14 -0000 1.15 +++ regress/sys/kern/kqueue/main.c 14 Aug 2023 14:52:43 -0000 @@ -17,8 +17,11 @@ main(int argc, char **argv) int n, ret, c; ret = 0; - while ((c = getopt(argc, argv, "fFiIjlpPrR:stT:")) != -1) { + while ((c = getopt(argc, argv, "efFiIjlpPrR:stT:")) != -1) { switch (c) { + case 'e': + ret |= do_exec(argv[0]); + break; case 'f': ret |= check_inheritance(); break; Index: regress/sys/kern/kqueue/main.h =================================================================== RCS file: src/regress/sys/kern/kqueue/main.h,v retrieving revision 1.6 diff -u -p -r1.6 main.h --- regress/sys/kern/kqueue/main.h 12 Jun 2021 13:30:14 -0000 1.6 +++ regress/sys/kern/kqueue/main.h 14 Aug 2023 14:52:43 -0000 @@ -16,6 +16,7 @@ __FILE__, __LINE__)) int check_inheritance(void); +int do_exec(const char *); int do_fdpass(void); int do_flock(void); int do_invalid_timer(void);