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