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);

Reply via email to