sys_kevent() and kqueue_scan() consume a relatively large amount of
kernel stack space, 352 and 544 bytes, respectively, on amd64. The
portion of kqueue_scan() can be reduced by 256 bytes to 288 bytes
by reusing sys_kevent()'s kev[] array.

This diff overlaps with the non-committed kqueue_scan() refactoring.
However, there is an unsolved system hang issue with the related
kqueue_scan_state patch. The change below reduces the likelihood of
kernel stack exhaustion, though it is unlikely that it would help with
the hang. I think the reduction of stack usage is useful in itself,
however.

The added asserts state that the retry branch should be taken only
if no events have been collected.

OK?

Index: kern/kern_event.c
===================================================================
RCS file: src/sys/kern/kern_event.c,v
retrieving revision 1.141
diff -u -p -r1.141 kern_event.c
--- kern/kern_event.c   4 Jul 2020 08:33:43 -0000       1.141
+++ kern/kern_event.c   9 Aug 2020 14:51:35 -0000
@@ -66,7 +66,7 @@ void  KQRELE(struct kqueue *);
 int    kqueue_sleep(struct kqueue *, struct timespec *);
 int    kqueue_scan(struct kqueue *kq, int maxevents,
                    struct kevent *ulistp, struct timespec *timeout,
-                   struct proc *p, int *retval);
+                   struct kevent *kev, struct proc *p, int *retval);
 
 int    kqueue_read(struct file *, struct uio *, int);
 int    kqueue_write(struct file *, struct uio *, int);
@@ -638,7 +638,7 @@ sys_kevent(struct proc *p, void *v, regi
        KQREF(kq);
        FRELE(fp, p);
        error = kqueue_scan(kq, SCARG(uap, nevents), SCARG(uap, eventlist),
-           tsp, p, &n);
+           tsp, kev, p, &n);
        KQRELE(kq);
        *retval = n;
        return (error);
@@ -896,12 +896,14 @@ kqueue_sleep(struct kqueue *kq, struct t
 
 int
 kqueue_scan(struct kqueue *kq, int maxevents, struct kevent *ulistp,
-    struct timespec *tsp, struct proc *p, int *retval)
+    struct timespec *tsp, struct kevent *kev, struct proc *p, int *retval)
 {
        struct kevent *kevp;
        struct knote mend, mstart, *kn;
-       int s, count, nkev = 0, error = 0;
-       struct kevent kev[KQ_NEVENTS];
+       int s, count, nkev, error = 0;
+
+       nkev = 0;
+       kevp = kev;
 
        count = maxevents;
        if (count == 0)
@@ -911,12 +913,14 @@ kqueue_scan(struct kqueue *kq, int maxev
        memset(&mend, 0, sizeof(mend));
 
 retry:
+       KASSERT(count == maxevents);
+       KASSERT(nkev == 0);
+
        if (kq->kq_state & KQ_DYING) {
                error = EBADF;
                goto done;
        }
 
-       kevp = &kev[0];
        s = splhigh();
        if (kq->kq_count == 0) {
                if (tsp != NULL && !timespecisset(tsp)) {
@@ -1019,7 +1023,7 @@ retry:
                            sizeof(struct kevent) * nkev);
                        ulistp += nkev;
                        nkev = 0;
-                       kevp = &kev[0];
+                       kevp = kev;
                        s = splhigh();
                        if (error)
                                break;

Reply via email to