Module Name: src Committed By: riastradh Date: Sat Sep 2 17:43:38 UTC 2023
Modified Files: src/sys/kern: kern_heartbeat.c src/sys/sys: sched.h Log Message: heartbeat(9): New flag SPCF_HEARTBEATSUSPENDED. This way we can suspend heartbeats on a single CPU while the console is in polling mode, not just when the CPU is offlined. This should be rare, so it's not _convenient_, but it should enable us to fix polling-mode console input when the hardclock timer is still running on other CPUs. To generate a diff of this commit: cvs rdiff -u -r1.5 -r1.6 src/sys/kern/kern_heartbeat.c cvs rdiff -u -r1.92 -r1.93 src/sys/sys/sched.h 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.5 src/sys/kern/kern_heartbeat.c:1.6 --- src/sys/kern/kern_heartbeat.c:1.5 Sun Jul 16 10:18:19 2023 +++ src/sys/kern/kern_heartbeat.c Sat Sep 2 17:43:37 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: kern_heartbeat.c,v 1.5 2023/07/16 10:18:19 riastradh Exp $ */ +/* $NetBSD: kern_heartbeat.c,v 1.6 2023/09/02 17:43:37 riastradh Exp $ */ /*- * Copyright (c) 2023 The NetBSD Foundation, Inc. @@ -78,7 +78,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_heartbeat.c,v 1.5 2023/07/16 10:18:19 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_heartbeat.c,v 1.6 2023/09/02 17:43:37 riastradh Exp $"); #ifdef _KERNEL_OPT #include "opt_ddb.h" @@ -127,17 +127,22 @@ void *heartbeat_sih __read_mostly; * Suspend heartbeat monitoring of the current CPU. * * Called after the current CPU has been marked offline but before - * it has stopped running. Caller must have preemption disabled. + * it has stopped running, or after IPL has been raised for + * polling-mode console input. Caller must have preemption + * disabled. Non-nestable. Reversed by heartbeat_resume. */ void heartbeat_suspend(void) { + struct cpu_info *ci = curcpu(); + int s; KASSERT(curcpu_stable()); + KASSERT((ci->ci_schedstate.spc_flags & SPCF_HEARTBEATSUSPENDED) == 0); - /* - * Nothing to do -- we just check the SPCF_OFFLINE flag. - */ + s = splsched(); + ci->ci_schedstate.spc_flags |= SPCF_HEARTBEATSUSPENDED; + splx(s); } /* @@ -148,6 +153,8 @@ heartbeat_suspend(void) * Called at startup while cold, and whenever heartbeat monitoring * is re-enabled after being disabled or the period is changed. * When not cold, ci must be the current CPU. + * + * Must be run at splsched. */ static void heartbeat_resume_cpu(struct cpu_info *ci) @@ -155,6 +162,7 @@ heartbeat_resume_cpu(struct cpu_info *ci KASSERT(__predict_false(cold) || curcpu_stable()); KASSERT(__predict_false(cold) || ci == curcpu()); + /* XXX KASSERT IPL_SCHED */ ci->ci_heartbeat_count = 0; ci->ci_heartbeat_uptime_cache = time_uptime; @@ -167,9 +175,8 @@ heartbeat_resume_cpu(struct cpu_info *ci * Resume heartbeat monitoring of the current CPU. * * Called after the current CPU has started running but before it - * has been marked online. Also used internally when starting up - * heartbeat monitoring at boot or when the maximum period is set - * from zero to nonzero. Caller must have preemption disabled. + * has been marked online, or when ending polling-mode input + * before IPL is restored. Caller must have preemption disabled. */ void heartbeat_resume(void) @@ -178,6 +185,7 @@ heartbeat_resume(void) int s; KASSERT(curcpu_stable()); + KASSERT(ci->ci_schedstate.spc_flags & SPCF_HEARTBEATSUSPENDED); /* * Block heartbeats while we reset the state so we don't @@ -185,6 +193,7 @@ heartbeat_resume(void) * resetting the count and the uptime stamp. */ s = splsched(); + ci->ci_schedstate.spc_flags &= ~SPCF_HEARTBEATSUSPENDED; heartbeat_resume_cpu(ci); splx(s); } @@ -198,8 +207,11 @@ heartbeat_resume(void) static void heartbeat_reset_xc(void *a, void *b) { + int s; - heartbeat_resume(); + s = splsched(); + heartbeat_resume_cpu(curcpu()); + splx(s); } /* @@ -488,7 +500,7 @@ select_patient(void) * in the iteration order. */ for (CPU_INFO_FOREACH(cii, ci)) { - if (ci->ci_schedstate.spc_flags & SPCF_OFFLINE) + if (ci->ci_schedstate.spc_flags & SPCF_HEARTBEATSUSPENDED) continue; if (passedcur) { /* @@ -565,7 +577,8 @@ heartbeat(void) period_secs = atomic_load_relaxed(&heartbeat_max_period_secs); if (__predict_false(period_ticks == 0) || __predict_false(period_secs == 0) || - __predict_false(curcpu()->ci_schedstate.spc_flags & SPCF_OFFLINE)) + __predict_false(curcpu()->ci_schedstate.spc_flags & + SPCF_HEARTBEATSUSPENDED)) return; /* @@ -637,8 +650,8 @@ heartbeat(void) * Verify that time is advancing on the patient CPU. If the * delta exceeds UINT_MAX/2, that means it is already ahead by * a little on the other CPU, and the subtraction went - * negative, which is OK. If the CPU has been - * offlined since we selected it, no worries. + * negative, which is OK. If the CPU's heartbeats have been + * suspended since we selected it, no worries. * * This uses the current CPU to ensure the other CPU has made * progress, even if the other CPU's hard timer interrupt @@ -650,7 +663,8 @@ heartbeat(void) d = uptime - atomic_load_relaxed(&patient->ci_heartbeat_uptime_cache); if (__predict_false(d > period_secs) && __predict_false(d < UINT_MAX/2) && - ((patient->ci_schedstate.spc_flags & SPCF_OFFLINE) == 0)) + ((patient->ci_schedstate.spc_flags & SPCF_HEARTBEATSUSPENDED) + == 0)) defibrillate(patient, d); } @@ -661,11 +675,21 @@ heartbeat(void) */ #ifdef DDB static unsigned -db_read_unsigned(const unsigned *p) +db_read_unsigned(const volatile unsigned *p) { unsigned x; - db_read_bytes((db_addr_t)p, sizeof(x), (char *)&x); + db_read_bytes((db_addr_t)(uintptr_t)p, sizeof(x), (char *)&x); + + return x; +} + +static int +db_read_signed(const volatile int *p) +{ + int x; + + db_read_bytes((db_addr_t)(uintptr_t)p, sizeof(x), (char *)&x); return x; } @@ -677,11 +701,13 @@ heartbeat_dump(void) db_printf("Heartbeats:\n"); for (ci = db_cpu_first(); ci != NULL; ci = db_cpu_next(ci)) { - db_printf("cpu%u: count %u uptime %u stamp %u\n", + db_printf("cpu%u: count %u uptime %u stamp %u%s\n", db_read_unsigned(&ci->ci_index), db_read_unsigned(&ci->ci_heartbeat_count), db_read_unsigned(&ci->ci_heartbeat_uptime_cache), - db_read_unsigned(&ci->ci_heartbeat_uptime_stamp)); + db_read_unsigned(&ci->ci_heartbeat_uptime_stamp), + (db_read_signed(&ci->ci_schedstate.spc_flags) & + SPCF_HEARTBEATSUSPENDED ? " (suspended)" : "")); } } #endif Index: src/sys/sys/sched.h diff -u src/sys/sys/sched.h:1.92 src/sys/sys/sched.h:1.93 --- src/sys/sys/sched.h:1.92 Thu Jul 13 12:06:20 2023 +++ src/sys/sys/sched.h Sat Sep 2 17:43:37 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: sched.h,v 1.92 2023/07/13 12:06:20 riastradh Exp $ */ +/* $NetBSD: sched.h,v 1.93 2023/09/02 17:43:37 riastradh Exp $ */ /*- * Copyright (c) 1999, 2000, 2001, 2002, 2007, 2008, 2019, 2020 @@ -188,6 +188,7 @@ struct schedstate_percpu { #define SPCF_1STCLASS 0x0040 /* first class scheduling entity */ #define SPCF_CORE1ST 0x0100 /* first CPU in core */ #define SPCF_PACKAGE1ST 0x0200 /* first CPU in package */ +#define SPCF_HEARTBEATSUSPENDED 0x0400 /* heartbeat (temporarily) suspended */ #define SPCF_SWITCHCLEAR (SPCF_SEENRR|SPCF_SHOULDYIELD)