Module Name:    src
Committed By:   riastradh
Date:           Sun Aug 25 01:14:01 UTC 2024

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

Log Message:
heartbeat(9): Use the cheaper and equally safe time_uptime32.

Since we cache this every 15sec, and check it within a tick, there's
no way for this to wrap around without first triggering a heartbeat
panic.  So just use time_uptime32, the low 32 bits of the number of
seconds of uptime -- cheaper on LP32 platforms.

PR kern/58633: heartbeat(9) makes unnecessary use of time_uptime


To generate a diff of this commit:
cvs rdiff -u -r1.13 -r1.14 src/sys/kern/kern_heartbeat.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_heartbeat.c
diff -u src/sys/kern/kern_heartbeat.c:1.13 src/sys/kern/kern_heartbeat.c:1.14
--- src/sys/kern/kern_heartbeat.c:1.13	Fri Mar  8 23:34:03 2024
+++ src/sys/kern/kern_heartbeat.c	Sun Aug 25 01:14:01 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_heartbeat.c,v 1.13 2024/03/08 23:34:03 riastradh Exp $	*/
+/*	$NetBSD: kern_heartbeat.c,v 1.14 2024/08/25 01:14:01 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2023 The NetBSD Foundation, Inc.
@@ -82,7 +82,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_heartbeat.c,v 1.13 2024/03/08 23:34:03 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_heartbeat.c,v 1.14 2024/08/25 01:14:01 riastradh Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ddb.h"
@@ -170,7 +170,7 @@ heartbeat_resume_cpu(struct cpu_info *ci
 	/* XXX KASSERT IPL_SCHED */
 
 	ci->ci_heartbeat_count = 0;
-	ci->ci_heartbeat_uptime_cache = time_uptime;
+	ci->ci_heartbeat_uptime_cache = time_uptime32;
 	ci->ci_heartbeat_uptime_stamp = 0;
 }
 
@@ -283,7 +283,7 @@ set_max_period(unsigned max_period)
 
 	/*
 	 * If we're enabling heartbeat checks, make sure we have a
-	 * reasonably up-to-date time_uptime cache on all CPUs so we
+	 * reasonably up-to-date time_uptime32 cache on all CPUs so we
 	 * don't think we had an instant heart attack.
 	 */
 	if (heartbeat_max_period_secs == 0 && max_period != 0) {
@@ -406,7 +406,7 @@ static void
 heartbeat_intr(void *cookie)
 {
 	unsigned count = atomic_load_relaxed(&curcpu()->ci_heartbeat_count);
-	unsigned uptime = time_uptime;
+	unsigned uptime = time_uptime32;
 
 	atomic_store_relaxed(&curcpu()->ci_heartbeat_uptime_stamp, count);
 	atomic_store_relaxed(&curcpu()->ci_heartbeat_uptime_cache, uptime);
@@ -420,7 +420,15 @@ heartbeat_intr(void *cookie)
 void
 heartbeat_start(void)
 {
-	const unsigned max_period = HEARTBEAT_MAX_PERIOD_DEFAULT;
+	enum { max_period = HEARTBEAT_MAX_PERIOD_DEFAULT };
+
+	/*
+	 * Ensure the maximum period is small enough that we never have
+	 * to worry about 32-bit wraparound even if there's a lot of
+	 * slop.  (In fact this is required to be less than
+	 * UINT_MAX/4/hz, but that's not a compile-time constant.)
+	 */
+	__CTASSERT(max_period < UINT_MAX/4);
 
 	/*
 	 * Establish a softint so we can schedule it once ready.  This
@@ -433,7 +441,7 @@ heartbeat_start(void)
 	/*
 	 * Now that the softint is established, kick off heartbeat
 	 * monitoring with the default period.  This will initialize
-	 * the per-CPU state to an up-to-date cache of time_uptime.
+	 * the per-CPU state to an up-to-date cache of time_uptime32.
 	 */
 	mutex_enter(&heartbeat_lock);
 	set_max_period(max_period);
@@ -651,7 +659,7 @@ heartbeat(void)
 	 * changed, and stop here -- we only do the cross-CPU work once
 	 * per second.
 	 */
-	uptime = time_uptime;
+	uptime = time_uptime32;
 	cache = atomic_load_relaxed(&curcpu()->ci_heartbeat_uptime_cache);
 	if (__predict_true(cache == uptime)) {
 		/*
@@ -661,7 +669,7 @@ heartbeat(void)
 		 * suspended too.
 		 *
 		 * Our own heartbeat count can't roll back, and
-		 * time_uptime should be updated before it wraps
+		 * time_uptime32 should be updated before it wraps
 		 * around, so d should never go negative; hence no
 		 * check for d < UINT_MAX/2.
 		 */
@@ -679,8 +687,10 @@ heartbeat(void)
 	/*
 	 * If the uptime has changed, make sure that it hasn't changed
 	 * so much that softints must be stuck on this CPU.  Since
-	 * time_uptime is monotonic, this can't go negative, hence no
-	 * check for d < UINT_MAX/2.
+	 * time_uptime32 is monotonic and our cache of it is updated at
+	 * most every UINT_MAX/4/hz sec (hence no concern about
+	 * wraparound even after 68 or 136 years), this can't go
+	 * negative, hence no check for d < UINT_MAX/2.
 	 *
 	 * This uses the hard timer interrupt handler on the current
 	 * CPU to ensure soft interrupts at all priority levels have

Reply via email to