Module Name:    src
Committed By:   thorpej
Date:           Thu Oct 21 01:11:21 UTC 2021

Modified Files:
        src/sys/kern: kern_event.c

Log Message:
Re-factor the code that computes the EVFILT_TIMER value into its own
function.

NFC.


To generate a diff of this commit:
cvs rdiff -u -r1.133 -r1.134 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.133 src/sys/kern/kern_event.c:1.134
--- src/sys/kern/kern_event.c:1.133	Thu Oct 21 00:54:15 2021
+++ src/sys/kern/kern_event.c	Thu Oct 21 01:11:21 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_event.c,v 1.133 2021/10/21 00:54:15 thorpej Exp $	*/
+/*	$NetBSD: kern_event.c,v 1.134 2021/10/21 01:11:21 thorpej Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2009, 2021 The NetBSD Foundation, Inc.
@@ -63,7 +63,7 @@
 #endif /* _KERNEL_OPT */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_event.c,v 1.133 2021/10/21 00:54:15 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_event.c,v 1.134 2021/10/21 01:11:21 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -1153,32 +1153,13 @@ knote_proc_exit(struct proc *p)
 
 #define	FILT_TIMER_NOSCHED	((uintptr_t)-1)
 
-static void
-filt_timerexpire(void *knx)
-{
-	struct knote *kn = knx;
-	struct kqueue *kq = kn->kn_kq;
-
-	mutex_spin_enter(&kq->kq_lock);
-	kn->kn_data++;
-	knote_activate_locked(kn);
-	if (kn->kn_sdata != FILT_TIMER_NOSCHED) {
-		KASSERT(kn->kn_sdata > 0 && kn->kn_sdata <= INT_MAX);
-		callout_schedule((callout_t *)kn->kn_hook,
-		    (int)kn->kn_sdata);
-	}
-	mutex_spin_exit(&kq->kq_lock);
-}
-
 static int
-filt_timerattach(struct knote *kn)
+filt_timercompute(struct kevent *kev, uintptr_t *tticksp)
 {
-	callout_t *calloutp;
-	struct kqueue *kq;
 	struct timespec ts;
-	int tticks, flags = 0;
+	uintptr_t tticks;
 
-	if (kn->kn_sfflags & ~(NOTE_TIMER_UNITMASK | NOTE_ABSTIME)) {
+	if (kev->fflags & ~(NOTE_TIMER_UNITMASK | NOTE_ABSTIME)) {
 		return EINVAL;
 	}
 
@@ -1186,32 +1167,32 @@ filt_timerattach(struct knote *kn)
 	 * Convert the event 'data' to a timespec, then convert the
 	 * timespec to callout ticks.
 	 */
-	switch (kn->kn_sfflags & NOTE_TIMER_UNITMASK) {
+	switch (kev->fflags & NOTE_TIMER_UNITMASK) {
 	case NOTE_SECONDS:
-		ts.tv_sec = kn->kn_sdata;
+		ts.tv_sec = kev->data;
 		ts.tv_nsec = 0;
 		break;
 
 	case NOTE_MSECONDS:		/* == historical value 0 */
-		ts.tv_sec = kn->kn_sdata / 1000;
-		ts.tv_nsec = (kn->kn_sdata % 1000) * 1000000;
+		ts.tv_sec = kev->data / 1000;
+		ts.tv_nsec = (kev->data % 1000) * 1000000;
 		break;
 
 	case NOTE_USECONDS:
-		ts.tv_sec = kn->kn_sdata / 1000000;
-		ts.tv_nsec = (kn->kn_sdata % 1000000) * 1000;
+		ts.tv_sec = kev->data / 1000000;
+		ts.tv_nsec = (kev->data % 1000000) * 1000;
 		break;
 
 	case NOTE_NSECONDS:
-		ts.tv_sec = kn->kn_sdata / 1000000000;
-		ts.tv_nsec = kn->kn_sdata % 1000000000;
+		ts.tv_sec = kev->data / 1000000000;
+		ts.tv_nsec = kev->data % 1000000000;
 		break;
 
 	default:
 		return EINVAL;
 	}
 
-	if (kn->kn_sfflags & NOTE_ABSTIME) {
+	if (kev->fflags & NOTE_ABSTIME) {
 		struct timespec deadline = ts;
 
 		/*
@@ -1222,35 +1203,81 @@ filt_timerattach(struct knote *kn)
 		 */
 		nanotime(&ts);
 
+		/* Absolute timers do not repeat. */
+		kev->data = FILT_TIMER_NOSCHED;
+
 		/* If we're past the deadline, then the event will fire. */
 		if (timespeccmp(&deadline, &ts, <=)) {
-			kn->kn_data = 1;
-			return 0;
+			tticks = FILT_TIMER_NOSCHED;
+			goto out;
 		}
 
 		/* Calculate how much time is left. */
 		timespecsub(&deadline, &ts, &ts);
 	} else {
 		/* EV_CLEAR automatically set for relative timers. */
-		flags |= EV_CLEAR;
+		kev->flags |= EV_CLEAR;
 	}
 
 	tticks = tstohz(&ts);
 
 	/* if the supplied value is under our resolution, use 1 tick */
 	if (tticks == 0) {
-		if (kn->kn_sdata == 0)
+		if (kev->data == 0)
 			return EINVAL;
 		tticks = 1;
+	} else if (tticks > INT_MAX) {
+		return EINVAL;
 	}
 
-	if ((kn->kn_flags & EV_ONESHOT) != 0 ||
-	    (kn->kn_sfflags & NOTE_ABSTIME) != 0) {
+	if ((kev->flags & EV_ONESHOT) != 0) {
 		/* Timer does not repeat. */
-		kn->kn_sdata = FILT_TIMER_NOSCHED;
+		kev->data = FILT_TIMER_NOSCHED;
 	} else {
 		KASSERT((uintptr_t)tticks != FILT_TIMER_NOSCHED);
-		kn->kn_sdata = tticks;
+		kev->data = tticks;
+	}
+
+ out:
+	*tticksp = tticks;
+
+	return 0;
+}
+
+static void
+filt_timerexpire(void *knx)
+{
+	struct knote *kn = knx;
+	struct kqueue *kq = kn->kn_kq;
+
+	mutex_spin_enter(&kq->kq_lock);
+	kn->kn_data++;
+	knote_activate_locked(kn);
+	if (kn->kn_sdata != FILT_TIMER_NOSCHED) {
+		KASSERT(kn->kn_sdata > 0 && kn->kn_sdata <= INT_MAX);
+		callout_schedule((callout_t *)kn->kn_hook,
+		    (int)kn->kn_sdata);
+	}
+	mutex_spin_exit(&kq->kq_lock);
+}
+
+static int
+filt_timerattach(struct knote *kn)
+{
+	callout_t *calloutp;
+	struct kqueue *kq;
+	uintptr_t tticks;
+	int error;
+
+	struct kevent kev = {
+		.flags = kn->kn_flags,
+		.fflags = kn->kn_sfflags,
+		.data = kn->kn_sdata,
+	};
+
+	error = filt_timercompute(&kev, &tticks);
+	if (error) {
+		return error;
 	}
 
 	if (atomic_inc_uint_nv(&kq_ncallouts) >= kq_calloutmax ||
@@ -1262,11 +1289,20 @@ filt_timerattach(struct knote *kn)
 
 	kq = kn->kn_kq;
 	mutex_spin_enter(&kq->kq_lock);
-	kn->kn_flags |= flags;
+
+	kn->kn_sdata = kev.data;
+	kn->kn_flags = kev.flags;
+	KASSERT(kn->kn_sfflags == kev.fflags);
 	kn->kn_hook = calloutp;
-	mutex_spin_exit(&kq->kq_lock);
 
-	callout_reset(calloutp, tticks, filt_timerexpire, kn);
+	if (__predict_false(tticks == FILT_TIMER_NOSCHED)) {
+		kn->kn_data = 1;
+	} else {
+		KASSERT(tticks <= INT_MAX);
+		callout_reset(calloutp, (int)tticks, filt_timerexpire, kn);
+	}
+
+	mutex_spin_exit(&kq->kq_lock);
 
 	return (0);
 }

Reply via email to