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