Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys implement fo_restart hook for kqueue descriptors, so tha...



details:   https://anonhg.NetBSD.org/src/rev/d547d186dfdf
branches:  trunk
changeset: 983083:d547d186dfdf
user:      jdolecek <jdolecek%NetBSD.org@localhost>
date:      Sun May 02 19:13:43 2021 +0000

description:
implement fo_restart hook for kqueue descriptors, so that close(2)
on the descriptor won't block indefinitely if other thread is currently
blocked on the same kqueue in kevent(2)

done similarily to pipes and sockets, i.e. using flag on the potentially
shared kqueue structure hooked off file_t - this is somewhat suboptimal
if the application dup(2)ped the descriptor, but this should be rare
enough to not really matter

usually this causes the kevent(2) to end up returning EBADF since
on the syscall restart the descriptor is not there anymore; if
dup(2)ped the kevent(2) call can continue successfully if the closed
kqueue descriptor was other than the one used for the kevent(2)
call

PR kern/46248 by Julian Fagir

diffstat:

 sys/kern/kern_event.c |  54 ++++++++++++++++++++++++++++++--------------------
 sys/sys/eventvar.h    |   6 +++-
 2 files changed, 36 insertions(+), 24 deletions(-)

diffs (173 lines):

diff -r fb0e20459f88 -r d547d186dfdf sys/kern/kern_event.c
--- a/sys/kern/kern_event.c     Sun May 02 15:22:27 2021 +0000
+++ b/sys/kern/kern_event.c     Sun May 02 19:13:43 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: kern_event.c,v 1.117 2021/01/27 06:59:08 skrll Exp $   */
+/*     $NetBSD: kern_event.c,v 1.118 2021/05/02 19:13:43 jdolecek Exp $        */
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -59,7 +59,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_event.c,v 1.117 2021/01/27 06:59:08 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_event.c,v 1.118 2021/05/02 19:13:43 jdolecek Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -90,6 +90,7 @@
 static int     kqueue_kqfilter(file_t *, struct knote *);
 static int     kqueue_stat(file_t *, struct stat *);
 static int     kqueue_close(file_t *);
+static void    kqueue_restart(file_t *);
 static int     kqueue_register(struct kqueue *, struct kevent *);
 static void    kqueue_doclose(struct kqueue *, struct klist *, int);
 
@@ -125,7 +126,7 @@
        .fo_stat = kqueue_stat,
        .fo_close = kqueue_close,
        .fo_kqfilter = kqueue_kqfilter,
-       .fo_restart = fnullop_restart,
+       .fo_restart = kqueue_restart,
 };
 
 static const struct filterops kqread_filtops = {
@@ -501,7 +502,7 @@
 
        if (hint != NOTE_SUBMIT)
                mutex_spin_enter(&kq->kq_lock);
-       kn->kn_data = kq->kq_count;
+       kn->kn_data = KQ_COUNT(kq);
        rv = (kn->kn_data > 0);
        if (hint != NOTE_SUBMIT)
                mutex_spin_exit(&kq->kq_lock);
@@ -1328,12 +1329,12 @@
 kqueue_check(const char *func, size_t line, const struct kqueue *kq)
 {
        const struct knote *kn;
-       int count;
+       u_int count;
        int nmarker;
        char buf[128];
 
        KASSERT(mutex_owned(&kq->kq_lock));
-       KASSERT(kq->kq_count >= 0);
+       KASSERT(KQ_COUNT(kq) < UINT_MAX / 2);
 
        count = 0;
        nmarker = 0;
@@ -1353,22 +1354,14 @@
                                    func, line, kq, kn, KN_FMT(buf, kn));
                        }
                        count++;
-                       if (count > kq->kq_count) {
+                       if (count > KQ_COUNT(kq)) {
                                panic("%s,%zu: kq=%p kq->kq_count(%d) != "
                                    "count(%d), nmarker=%d",
-                                   func, line, kq, kq->kq_count, count,
+                                   func, line, kq, KQ_COUNT(kq), count,
                                    nmarker);
                        }
                } else {
                        nmarker++;
-#if 0
-                       if (nmarker > 10000) {
-                               panic("%s,%zu: kq=%p too many markers: "
-                                   "%d != %d, nmarker=%d",
-                                   func, line, kq, kq->kq_count, count,
-                                   nmarker);
-                       }
-#endif
                }
        }
 }
@@ -1377,6 +1370,18 @@
 #define        kq_check(a)     /* nothing */
 #endif /* defined(DEBUG) */
 
+static void
+kqueue_restart(file_t *fp)
+{
+       struct kqueue *kq = fp->f_kqueue;
+       KASSERT(kq != NULL);
+
+       mutex_spin_enter(&kq->kq_lock);
+       kq->kq_count |= KQ_RESTART;
+       cv_broadcast(&kq->kq_cv);
+       mutex_spin_exit(&kq->kq_lock);
+}
+
 /*
  * Scan through the list of events on fp (for a maximum of maxevents),
  * returning the results in to ulistp. Timeout is determined by tsp; if
@@ -1426,14 +1431,19 @@
        mutex_spin_enter(&kq->kq_lock);
  retry:
        kevp = kevbuf;
-       if (kq->kq_count == 0) {
+       if (KQ_COUNT(kq) == 0) {
                if (timeout >= 0) {
                        error = cv_timedwait_sig(&kq->kq_cv,
                            &kq->kq_lock, timeout);
                        if (error == 0) {
-                                if (tsp == NULL || (timeout =
-                                    gettimeleft(&ats, &sleepts)) > 0)
+                               if (KQ_COUNT(kq) == 0 &&
+                                   (kq->kq_count & KQ_RESTART)) {
+                                       /* return to clear file reference */
+                                       error = ERESTART;
+                               } else if (tsp == NULL || (timeout =
+                                   gettimeleft(&ats, &sleepts)) > 0) {
                                        goto retry;
+                               }
                        } else {
                                /* don't restart after signals... */
                                if (error == ERESTART)
@@ -1689,7 +1699,7 @@
        revents = 0;
        if (events & (POLLIN | POLLRDNORM)) {
                mutex_spin_enter(&kq->kq_lock);
-               if (kq->kq_count != 0) {
+               if (KQ_COUNT(kq) != 0) {
                        revents |= events & (POLLIN | POLLRDNORM);
                } else {
                        selrecord(curlwp, &kq->kq_sel);
@@ -1713,7 +1723,7 @@
        kq = fp->f_kqueue;
 
        memset(st, 0, sizeof(*st));
-       st->st_size = kq->kq_count;
+       st->st_size = KQ_COUNT(kq);
        st->st_blksize = sizeof(struct kevent);
        st->st_mode = S_IFIFO;
 
@@ -1771,7 +1781,7 @@
        }
        mutex_exit(&fdp->fd_lock);
 
-       KASSERT(kq->kq_count == 0);
+       KASSERT(KQ_COUNT(kq) == 0);
        mutex_destroy(&kq->kq_lock);
        cv_destroy(&kq->kq_cv);
        seldestroy(&kq->kq_sel);
diff -r fb0e20459f88 -r d547d186dfdf sys/sys/eventvar.h
--- a/sys/sys/eventvar.h        Sun May 02 15:22:27 2021 +0000
+++ b/sys/sys/eventvar.h        Sun May 02 19:13:43 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: eventvar.h,v 1.8 2008/03/21 21:53:35 ad Exp $  */
+/*     $NetBSD: eventvar.h,v 1.9 2021/05/02 19:13:43 jdolecek Exp $    */
 
 /*-
  * Copyright (c) 1999,2000 Jonathan Lemon <jlemon%FreeBSD.org@localhost>
@@ -51,7 +51,9 @@
        filedesc_t      *kq_fdp;
        struct selinfo  kq_sel;
        kcondvar_t      kq_cv;
-       int             kq_count;               /* number of pending events */
+       u_int           kq_count;               /* number of pending events */
+#define        KQ_RESTART      0x80000000              /* force ERESTART */
+#define KQ_COUNT(kq)   ((kq)->kq_count & ~KQ_RESTART)
 };
 
 #endif /* !_SYS_EVENTVAR_H_ */



Home | Main Index | Thread Index | Old Index