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

Reply via email to