Module Name: src
Committed By: thorpej
Date: Sun Sep 26 23:34:46 UTC 2021
Modified Files:
src/sys/kern: kern_event.c
Log Message:
- Rename kqueue_misc_lock -> kqueue_timer_lock, since EVFILT_TIMER is
now its only user. Also initialize it as IPL_SOFTCLOCK; there is no
practical difference in how it operates (it is still an adaptive lock),
but this serves as a visual reminder that we are interlocking against
a callout.
- Add some comments that describe why we don't need to hold kqueue_timer_lock
when detaching an EVFILT_TIMER due to guarantees made by callout_halt().
- Mark timer_filtops as MPSAFE.
To generate a diff of this commit:
cvs rdiff -u -r1.124 -r1.125 src/sys/kern/kern_event.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/kern/kern_event.c
diff -u src/sys/kern/kern_event.c:1.124 src/sys/kern/kern_event.c:1.125
--- src/sys/kern/kern_event.c:1.124 Sun Sep 26 21:29:38 2021
+++ src/sys/kern/kern_event.c Sun Sep 26 23:34:46 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: kern_event.c,v 1.124 2021/09/26 21:29:38 thorpej Exp $ */
+/* $NetBSD: kern_event.c,v 1.125 2021/09/26 23:34:46 thorpej 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.124 2021/09/26 21:29:38 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_event.c,v 1.125 2021/09/26 23:34:46 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -154,7 +154,7 @@ static const struct filterops file_filto
};
static const struct filterops timer_filtops = {
- .f_flags = 0,
+ .f_flags = FILTEROP_MPSAFE,
.f_attach = filt_timerattach,
.f_detach = filt_timerdetach,
.f_event = filt_timer,
@@ -222,7 +222,7 @@ static size_t user_kfiltersz; /* size
*
* kqueue_filter_lock
* -> kn_kq->kq_fdp->fd_lock
- * -> object lock (e.g., device driver lock, kqueue_misc_lock, &c.)
+ * -> object lock (e.g., device driver lock, &c.)
* -> kn_kq->kq_lock
*
* Locking rules:
@@ -236,7 +236,7 @@ static size_t user_kfiltersz; /* size
* acquires/releases object lock inside.
*/
static krwlock_t kqueue_filter_lock; /* lock on filter lists */
-static kmutex_t kqueue_misc_lock; /* miscellaneous */
+static kmutex_t kqueue_timer_lock; /* for EVFILT_TIMER */
static int
filter_attach(struct knote *kn)
@@ -333,7 +333,7 @@ kqueue_init(void)
{
rw_init(&kqueue_filter_lock);
- mutex_init(&kqueue_misc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&kqueue_timer_lock, MUTEX_DEFAULT, IPL_SOFTCLOCK);
kqueue_listener = kauth_listen_scope(KAUTH_SCOPE_PROCESS,
kqueue_listener_cb, NULL);
@@ -735,7 +735,7 @@ filt_timerexpire(void *knx)
struct knote *kn = knx;
int tticks;
- mutex_enter(&kqueue_misc_lock);
+ mutex_enter(&kqueue_timer_lock);
kn->kn_data++;
knote_activate(kn);
if ((kn->kn_flags & EV_ONESHOT) == 0) {
@@ -744,7 +744,7 @@ filt_timerexpire(void *knx)
tticks = 1;
callout_schedule((callout_t *)kn->kn_hook, tticks);
}
- mutex_exit(&kqueue_misc_lock);
+ mutex_exit(&kqueue_timer_lock);
}
/*
@@ -790,13 +790,27 @@ filt_timerdetach(struct knote *kn)
callout_t *calloutp;
struct kqueue *kq = kn->kn_kq;
+ /*
+ * We don't need to hold the kqueue_timer_lock here; even
+ * if filt_timerexpire() misses our setting of EV_ONESHOT,
+ * we are guaranteed that the callout will no longer be
+ * scheduled even if we attempted to halt it after it already
+ * started running, even if it rescheduled itself.
+ */
+
mutex_spin_enter(&kq->kq_lock);
/* prevent rescheduling when we expire */
kn->kn_flags |= EV_ONESHOT;
mutex_spin_exit(&kq->kq_lock);
calloutp = (callout_t *)kn->kn_hook;
+
+ /*
+ * Attempt to stop the callout. This will block if it's
+ * already running.
+ */
callout_halt(calloutp, NULL);
+
callout_destroy(calloutp);
kmem_free(calloutp, sizeof(*calloutp));
atomic_dec_uint(&kq_ncallouts);
@@ -807,9 +821,9 @@ filt_timer(struct knote *kn, long hint)
{
int rv;
- mutex_enter(&kqueue_misc_lock);
+ mutex_enter(&kqueue_timer_lock);
rv = (kn->kn_data != 0);
- mutex_exit(&kqueue_misc_lock);
+ mutex_exit(&kqueue_timer_lock);
return rv;
}