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