1 /* $NetBSD: kern_heartbeat.c,v 1.15 2026/01/04 01:34:05 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2023 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * heartbeat(9) -- periodic checks to ensure CPUs are making progress 31 * 32 * Manual tests to run when changing this file. Magic numbers are for 33 * evbarm; adjust for other platforms. Tests involving cpuctl 34 * online/offline assume a 2-CPU system -- for full testing on a >2-CPU 35 * system, offline all but one CPU. 36 * 37 * 1. cpuctl offline 0 38 * sleep 20 39 * cpuctl online 0 40 * 41 * 2. cpuctl offline 1 42 * sleep 20 43 * cpuctl online 1 44 * 45 * 3. cpuctl offline 0 46 * sysctl -w kern.heartbeat.max_period=5 47 * sleep 10 48 * sysctl -w kern.heartbeat.max_period=0 49 * sleep 10 50 * sysctl -w kern.heartbeat.max_period=5 51 * sleep 10 52 * cpuctl online 0 53 * 54 * 4. sysctl -w debug.crashme_enable=1 55 * sysctl -w debug.crashme.spl_spinout=1 # IPL_SOFTCLOCK 56 * # verify system panics after 15sec, with a stack trace through 57 * # crashme_spl_spinout 58 * 59 * 5. sysctl -w debug.crashme_enable=1 60 * sysctl -w debug.crashme.spl_spinout=6 # IPL_SCHED 61 * # verify system panics after 15sec, with a stack trace through 62 * # crashme_spl_spinout 63 * 64 * 6. cpuctl offline 0 65 * sysctl -w debug.crashme_enable=1 66 * sysctl -w debug.crashme.spl_spinout=1 # IPL_SOFTCLOCK 67 * # verify system panics after 15sec, with a stack trace through 68 * # crashme_spl_spinout 69 * 70 * 7. cpuctl offline 0 71 * sysctl -w debug.crashme_enable=1 72 * sysctl -w debug.crashme.spl_spinout=5 # IPL_VM 73 * # verify system panics after 15sec, with a stack trace through 74 * # crashme_spl_spinout 75 * 76 * # Not this -- IPL_SCHED and IPL_HIGH spinout on a single CPU 77 * # require a hardware watchdog timer. 78 * #cpuctl offline 0 79 * #sysctl -w debug.crashme_enable 80 * #sysctl -w debug.crashme.spl_spinout=6 # IPL_SCHED 81 * # hope watchdog timer kicks in 82 */ 83 84 #include <sys/cdefs.h> 85 __KERNEL_RCSID(0, "$NetBSD: kern_heartbeat.c,v 1.15 2026/01/04 01:34:05 riastradh Exp $"); 86 87 #ifdef _KERNEL_OPT 88 #include "opt_ddb.h" 89 #include "opt_heartbeat.h" 90 #endif 91 92 #include "heartbeat.h" 93 94 #include <sys/param.h> 95 #include <sys/types.h> 96 97 #include <sys/atomic.h> 98 #include <sys/cpu.h> 99 #include <sys/errno.h> 100 #include <sys/heartbeat.h> 101 #include <sys/ipi.h> 102 #include <sys/kernel.h> 103 #include <sys/mutex.h> 104 #include <sys/sdt.h> 105 #include <sys/sysctl.h> 106 #include <sys/systm.h> 107 #include <sys/xcall.h> 108 109 #ifdef DDB 110 #include <ddb/ddb.h> 111 #endif 112 113 /* 114 * Global state. 115 * 116 * heartbeat_lock serializes access to heartbeat_max_period_secs 117 * and heartbeat_max_period_ticks. Two separate variables so we 118 * can avoid multiplication or division in the heartbeat routine. 119 * 120 * heartbeat_sih is stable after initialization in 121 * heartbeat_start. 122 */ 123 kmutex_t heartbeat_lock __cacheline_aligned; 124 unsigned heartbeat_max_period_secs __read_mostly; 125 unsigned heartbeat_max_period_ticks __read_mostly; 126 127 void *heartbeat_sih __read_mostly; 128 129 /* 130 * heartbeat_suspend() 131 * 132 * Suspend heartbeat monitoring of the current CPU. 133 * 134 * Called after the current CPU has been marked offline but before 135 * it has stopped running, or after IPL has been raised for 136 * polling-mode console input. Nestable (but only 2^32 times, so 137 * don't do this in a loop). Reversed by heartbeat_resume. 138 * 139 * Caller must be bound to the CPU, i.e., curcpu_stable() must be 140 * true. This function does not assert curcpu_stable() since it 141 * is used in the ddb entry path, where any assertions risk 142 * infinite regress into undebuggable chaos, so callers must be 143 * careful. 144 */ 145 void 146 heartbeat_suspend(void) 147 { 148 unsigned *p; 149 150 p = &curcpu()->ci_heartbeat_suspend; 151 atomic_store_relaxed(p, *p + 1); 152 } 153 154 /* 155 * heartbeat_resume_cpu(ci) 156 * 157 * Resume heartbeat monitoring of ci. 158 * 159 * Called at startup while cold, and whenever heartbeat monitoring 160 * is re-enabled after being disabled or the period is changed. 161 * When not cold, ci must be the current CPU. 162 * 163 * Must be run at splsched. 164 */ 165 static void 166 heartbeat_resume_cpu(struct cpu_info *ci) 167 { 168 169 KASSERT(__predict_false(cold) || curcpu_stable()); 170 KASSERT(__predict_false(cold) || ci == curcpu()); 171 /* XXX KASSERT IPL_SCHED */ 172 173 ci->ci_heartbeat_count = 0; 174 ci->ci_heartbeat_uptime_cache = time_uptime32; 175 ci->ci_heartbeat_uptime_stamp = 0; 176 } 177 178 /* 179 * heartbeat_resume() 180 * 181 * Resume heartbeat monitoring of the current CPU. 182 * 183 * Called after the current CPU has started running but before it 184 * has been marked online, or when ending polling-mode input 185 * before IPL is restored. Reverses heartbeat_suspend. 186 * 187 * Caller must be bound to the CPU, i.e., curcpu_stable() must be 188 * true. 189 */ 190 void 191 heartbeat_resume(void) 192 { 193 struct cpu_info *ci = curcpu(); 194 unsigned *p; 195 int s; 196 197 KASSERT(curcpu_stable()); 198 199 /* 200 * Reset the state so nobody spuriously thinks we had a heart 201 * attack as soon as the heartbeat checks resume. 202 */ 203 s = splsched(); 204 heartbeat_resume_cpu(ci); 205 splx(s); 206 207 p = &ci->ci_heartbeat_suspend; 208 atomic_store_relaxed(p, *p - 1); 209 } 210 211 /* 212 * heartbeat_timecounter_suspended() 213 * 214 * True if timecounter heartbeat checks are suspended because the 215 * timecounter may not be advancing, false if heartbeat checks 216 * should check for timecounter progress. 217 */ 218 static bool 219 heartbeat_timecounter_suspended(void) 220 { 221 CPU_INFO_ITERATOR cii; 222 struct cpu_info *ci; 223 224 /* 225 * The timecounter ticks only on the primary CPU. Check 226 * whether it's suspended. 227 * 228 * XXX Would be nice if we could find the primary CPU without 229 * iterating over all CPUs. 230 */ 231 for (CPU_INFO_FOREACH(cii, ci)) { 232 if (CPU_IS_PRIMARY(ci)) 233 return atomic_load_relaxed(&ci->ci_heartbeat_suspend); 234 } 235 236 /* 237 * This should be unreachable -- there had better be a primary 238 * CPU in the system! If not, the timecounter will be busted 239 * anyway. 240 */ 241 panic("no primary CPU"); 242 } 243 244 /* 245 * heartbeat_reset_xc(a, b) 246 * 247 * Cross-call handler to reset heartbeat state just prior to 248 * enabling heartbeat checks. 249 */ 250 static void 251 heartbeat_reset_xc(void *a, void *b) 252 { 253 int s; 254 255 s = splsched(); 256 heartbeat_resume_cpu(curcpu()); 257 splx(s); 258 } 259 260 /* 261 * set_max_period(max_period) 262 * 263 * Set the maximum period, in seconds, for heartbeat checks. 264 * 265 * - If max_period is zero, disable them. 266 * 267 * - If the max period was zero and max_period is nonzero, ensure 268 * all CPUs' heartbeat uptime caches are up-to-date before 269 * re-enabling them. 270 * 271 * max_period must be below UINT_MAX/4/hz to avoid arithmetic 272 * overflow and give room for slop. 273 * 274 * Caller must hold heartbeat_lock. 275 */ 276 static void 277 set_max_period(unsigned max_period) 278 { 279 280 KASSERTMSG(max_period <= UINT_MAX/4/hz, 281 "max_period=%u must not exceed UINT_MAX/4/hz=%u (hz=%u)", 282 max_period, UINT_MAX/4/hz, hz); 283 KASSERT(mutex_owned(&heartbeat_lock)); 284 285 /* 286 * If we're enabling heartbeat checks, make sure we have a 287 * reasonably up-to-date time_uptime32 cache on all CPUs so we 288 * don't think we had an instant heart attack. 289 */ 290 if (heartbeat_max_period_secs == 0 && max_period != 0) { 291 if (cold) { 292 CPU_INFO_ITERATOR cii; 293 struct cpu_info *ci; 294 295 for (CPU_INFO_FOREACH(cii, ci)) 296 heartbeat_resume_cpu(ci); 297 } else { 298 const uint64_t ticket = 299 xc_broadcast(0, &heartbeat_reset_xc, NULL, NULL); 300 xc_wait(ticket); 301 } 302 } 303 304 /* 305 * Once the heartbeat state has been updated on all (online) 306 * CPUs, set the period. At this point, heartbeat checks can 307 * begin. 308 */ 309 atomic_store_relaxed(&heartbeat_max_period_secs, max_period); 310 atomic_store_relaxed(&heartbeat_max_period_ticks, max_period*hz); 311 } 312 313 /* 314 * heartbeat_max_period_ticks(SYSCTLFN_ARGS) 315 * 316 * Sysctl handler for sysctl kern.heartbeat.max_period. Verifies 317 * it lies within a reasonable interval and sets it. 318 */ 319 static int 320 heartbeat_max_period_sysctl(SYSCTLFN_ARGS) 321 { 322 struct sysctlnode node; 323 unsigned max_period; 324 int error; 325 326 mutex_enter(&heartbeat_lock); 327 328 max_period = heartbeat_max_period_secs; 329 node = *rnode; 330 node.sysctl_data = &max_period; 331 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 332 if (error || newp == NULL) 333 goto out; 334 335 /* 336 * Ensure there's plenty of slop between heartbeats. 337 */ 338 if (max_period > UINT_MAX/4/hz) { 339 error = SET_ERROR(EOVERFLOW); 340 goto out; 341 } 342 343 /* 344 * Success! Set the period. This enables heartbeat checks if 345 * we went from zero period to nonzero period, or disables them 346 * if the other way around. 347 */ 348 set_max_period(max_period); 349 error = 0; 350 351 out: mutex_exit(&heartbeat_lock); 352 return error; 353 } 354 355 /* 356 * sysctl_heartbeat_setup() 357 * 358 * Set up the kern.heartbeat.* sysctl subtree. 359 */ 360 SYSCTL_SETUP(sysctl_heartbeat_setup, "sysctl kern.heartbeat setup") 361 { 362 const struct sysctlnode *rnode; 363 int error; 364 365 mutex_init(&heartbeat_lock, MUTEX_DEFAULT, IPL_NONE); 366 367 /* kern.heartbeat */ 368 error = sysctl_createv(NULL, 0, NULL, &rnode, 369 CTLFLAG_PERMANENT, 370 CTLTYPE_NODE, "heartbeat", 371 SYSCTL_DESCR("Kernel heartbeat parameters"), 372 NULL, 0, NULL, 0, 373 CTL_KERN, CTL_CREATE, CTL_EOL); 374 if (error) { 375 printf("%s: failed to create kern.heartbeat: %d\n", 376 __func__, error); 377 return; 378 } 379 380 /* kern.heartbeat.max_period */ 381 error = sysctl_createv(NULL, 0, &rnode, NULL, 382 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 383 CTLTYPE_INT, "max_period", 384 SYSCTL_DESCR("Max seconds between heartbeats before panic"), 385 &heartbeat_max_period_sysctl, 0, NULL, 0, 386 CTL_CREATE, CTL_EOL); 387 if (error) { 388 printf("%s: failed to create kern.heartbeat.max_period: %d\n", 389 __func__, error); 390 return; 391 } 392 } 393 394 /* 395 * heartbeat_intr(cookie) 396 * 397 * Soft interrupt handler to update the local CPU's view of the 398 * system uptime. This runs at the same priority level as 399 * callouts, so if callouts are stuck on this CPU, it won't run, 400 * and eventually another CPU will notice that this one is stuck. 401 * 402 * Don't do spl* here -- keep it to a minimum so if anything goes 403 * wrong we don't end up with hard interrupts blocked and unable 404 * to detect a missed heartbeat. 405 */ 406 static void 407 heartbeat_intr(void *cookie) 408 { 409 unsigned count = atomic_load_relaxed(&curcpu()->ci_heartbeat_count); 410 unsigned uptime = time_uptime32; 411 412 atomic_store_relaxed(&curcpu()->ci_heartbeat_uptime_stamp, count); 413 atomic_store_relaxed(&curcpu()->ci_heartbeat_uptime_cache, uptime); 414 } 415 416 /* 417 * heartbeat_start() 418 * 419 * Start system heartbeat monitoring. 420 */ 421 void 422 heartbeat_start(void) 423 { 424 enum { max_period = HEARTBEAT_MAX_PERIOD_DEFAULT }; 425 426 /* 427 * Ensure the maximum period is small enough that we never have 428 * to worry about 32-bit wraparound even if there's a lot of 429 * slop. (In fact this is required to be less than 430 * UINT_MAX/4/hz, but that's not a compile-time constant.) 431 */ 432 __CTASSERT(max_period < UINT_MAX/4); 433 434 /* 435 * Establish a softint so we can schedule it once ready. This 436 * should be at the lowest softint priority level so that we 437 * ensure all softint priorities are making progress. 438 */ 439 heartbeat_sih = softint_establish(SOFTINT_CLOCK|SOFTINT_MPSAFE, 440 &heartbeat_intr, NULL); 441 442 /* 443 * Now that the softint is established, kick off heartbeat 444 * monitoring with the default period. This will initialize 445 * the per-CPU state to an up-to-date cache of time_uptime32. 446 */ 447 mutex_enter(&heartbeat_lock); 448 set_max_period(max_period); 449 mutex_exit(&heartbeat_lock); 450 } 451 452 /* 453 * defibrillator(cookie) 454 * 455 * IPI handler for defibrillation. If the CPU's heart has stopped 456 * beating normally, but the CPU can still execute things, 457 * acknowledge the IPI to the doctor and then panic so we at least 458 * get a stack trace from whatever the current CPU is stuck doing, 459 * if not a core dump. 460 * 461 * (This metaphor is a little stretched, since defibrillation is 462 * usually administered when the heart is beating errattically but 463 * hasn't stopped, and causes the heart to stop temporarily, and 464 * one hopes it is not fatal. But we're (software) engineers, so 465 * we can stretch metaphors like silly putty in a blender.) 466 */ 467 static void 468 defibrillator(void *cookie) 469 { 470 bool *ack = cookie; 471 472 /* 473 * Acknowledge the interrupt so the doctor CPU won't trigger a 474 * new panic for defibrillation timeout. 475 */ 476 atomic_store_relaxed(ack, true); 477 478 /* 479 * If a panic is already in progress, we may have interrupted 480 * the logic that prints a stack trace on this CPU -- so let's 481 * not make it worse by giving the misapprehension of a 482 * recursive panic. 483 */ 484 if (atomic_load_relaxed(&panicstr) != NULL) 485 return; 486 487 panic("%s[%d %s]: heart stopped beating", cpu_name(curcpu()), 488 curlwp->l_lid, 489 curlwp->l_name ? curlwp->l_name : curproc->p_comm); 490 } 491 492 /* 493 * defibrillate(ci, unsigned d) 494 * 495 * The patient CPU ci's heart has stopped beating after d seconds. 496 * Force the patient CPU ci to panic, or panic on this CPU if the 497 * patient CPU doesn't respond within 1sec. 498 */ 499 static void __noinline 500 defibrillate(struct cpu_info *ci, unsigned d) 501 { 502 bool ack = false; 503 ipi_msg_t msg = { 504 .func = &defibrillator, 505 .arg = &ack, 506 }; 507 unsigned countdown = 1000; /* 1sec */ 508 509 KASSERT(curcpu_stable()); 510 511 /* 512 * First notify the console that the patient CPU's heart seems 513 * to have stopped beating. 514 */ 515 printf("%s: found %s heart stopped beating after %u seconds\n", 516 cpu_name(curcpu()), cpu_name(ci), d); 517 518 /* 519 * Next, give the patient CPU a chance to panic, so we get a 520 * stack trace on that CPU even if we don't get a crash dump. 521 */ 522 ipi_unicast(&msg, ci); 523 524 /* 525 * Busy-wait up to 1sec for the patient CPU to print a stack 526 * trace and panic. If the patient CPU acknowledges the IPI, 527 * just give up and stop here -- the system is coming down soon 528 * and we should avoid getting in the way. 529 */ 530 while (countdown --> 0) { 531 if (atomic_load_relaxed(&ack)) 532 return; 533 DELAY(1000); /* 1ms */ 534 } 535 536 /* 537 * The patient CPU failed to acknowledge the panic request. 538 * Panic now; with any luck, we'll get a crash dump. 539 */ 540 panic("%s: found %s heart stopped beating and unresponsive", 541 cpu_name(curcpu()), cpu_name(ci)); 542 } 543 544 /* 545 * select_patient() 546 * 547 * Select another CPU to check the heartbeat of. Returns NULL if 548 * there are no other online CPUs. Never returns curcpu(). 549 * Caller must have kpreemption disabled. 550 */ 551 static struct cpu_info * 552 select_patient(void) 553 { 554 CPU_INFO_ITERATOR cii; 555 struct cpu_info *first = NULL, *patient = NULL, *ci; 556 bool passedcur = false; 557 558 KASSERT(curcpu_stable()); 559 560 /* 561 * In the iteration order of all CPUs, find the next online CPU 562 * after curcpu(), or the first online one if curcpu() is last 563 * in the iteration order. 564 */ 565 for (CPU_INFO_FOREACH(cii, ci)) { 566 if (atomic_load_relaxed(&ci->ci_heartbeat_suspend)) 567 continue; 568 if (passedcur) { 569 /* 570 * (...|curcpu()|ci|...) 571 * 572 * Found the patient right after curcpu(). 573 */ 574 KASSERT(patient != ci); 575 patient = ci; 576 break; 577 } 578 if (ci == curcpu()) { 579 /* 580 * (...|prev|ci=curcpu()|next|...) 581 * 582 * Note that we want next (or first, if there's 583 * nothing after curcpu()). 584 */ 585 passedcur = true; 586 continue; 587 } 588 if (first == NULL) { 589 /* 590 * (ci|...|curcpu()|...) 591 * 592 * Record ci as first in case there's nothing 593 * after curcpu(). 594 */ 595 first = ci; 596 continue; 597 } 598 } 599 600 /* 601 * If we hit the end, wrap around to the beginning. 602 */ 603 if (patient == NULL) { 604 KASSERT(passedcur); 605 patient = first; 606 } 607 608 return patient; 609 } 610 611 /* 612 * heartbeat() 613 * 614 * 1. Count a heartbeat on the local CPU. 615 * 616 * 2. Panic if the system uptime doesn't seem to have advanced in 617 * a while. 618 * 619 * 3. Panic if the soft interrupt on this CPU hasn't advanced the 620 * local view of the system uptime. 621 * 622 * 4. Schedule the soft interrupt to advance the local view of the 623 * system uptime. 624 * 625 * 5. Select another CPU to check the heartbeat of. 626 * 627 * 6. Panic if the other CPU hasn't advanced its view of the 628 * system uptime in a while. 629 */ 630 void 631 heartbeat(void) 632 { 633 unsigned period_ticks, period_secs; 634 unsigned count, uptime, cache, stamp, d; 635 struct cpu_info *patient; 636 637 KASSERT(curcpu_stable()); 638 639 /* 640 * If heartbeat checks are disabled globally, or if they are 641 * suspended locally, or if we're already panicking so it's not 642 * helpful to trigger more panics for more reasons, do nothing. 643 */ 644 period_ticks = atomic_load_relaxed(&heartbeat_max_period_ticks); 645 period_secs = atomic_load_relaxed(&heartbeat_max_period_secs); 646 if (__predict_false(period_ticks == 0) || 647 __predict_false(period_secs == 0) || 648 __predict_false(curcpu()->ci_heartbeat_suspend) || 649 __predict_false(panicstr != NULL)) 650 return; 651 652 /* 653 * Count a heartbeat on this CPU. 654 */ 655 count = curcpu()->ci_heartbeat_count++; 656 657 /* 658 * If the uptime hasn't changed, make sure that we haven't 659 * counted too many of our own heartbeats since the uptime last 660 * changed, and stop here -- we only do the cross-CPU work once 661 * per second. 662 */ 663 uptime = time_uptime32; 664 cache = atomic_load_relaxed(&curcpu()->ci_heartbeat_uptime_cache); 665 if (__predict_true(cache == uptime)) { 666 /* 667 * Timecounter hasn't advanced by more than a second. 668 * Make sure the timecounter isn't stuck according to 669 * our heartbeats -- unless timecounter heartbeats are 670 * suspended too. 671 * 672 * Our own heartbeat count can't roll back, and 673 * time_uptime32 should be updated before it wraps 674 * around, so d should never go negative; hence no 675 * check for d < UINT_MAX/2. 676 */ 677 stamp = 678 atomic_load_relaxed(&curcpu()->ci_heartbeat_uptime_stamp); 679 d = count - stamp; 680 if (__predict_false(d > period_ticks) && 681 !heartbeat_timecounter_suspended()) { 682 panic("%s: time has not advanced in %u heartbeats", 683 cpu_name(curcpu()), d); 684 } 685 return; 686 } 687 688 /* 689 * If the uptime has changed, make sure that it hasn't changed 690 * so much that softints must be stuck on this CPU. Since 691 * time_uptime32 is monotonic and our cache of it is updated at 692 * most every UINT_MAX/4/hz sec (hence no concern about 693 * wraparound even after 68 or 136 years), this can't go 694 * negative, hence no check for d < UINT_MAX/2. 695 * 696 * This uses the hard timer interrupt handler on the current 697 * CPU to ensure soft interrupts at all priority levels have 698 * made progress. 699 */ 700 d = uptime - cache; 701 if (__predict_false(d > period_secs)) { 702 panic("%s: softints stuck for %u seconds", 703 cpu_name(curcpu()), d); 704 } 705 706 /* 707 * Schedule a softint to update our cache of the system uptime 708 * so the next call to heartbeat, on this or another CPU, can 709 * detect progress on this one. 710 */ 711 softint_schedule(heartbeat_sih); 712 713 /* 714 * Select a patient to check the heartbeat of. If there's no 715 * other online CPU, nothing to do. 716 */ 717 patient = select_patient(); 718 if (patient == NULL) 719 return; 720 721 /* 722 * Verify that time is advancing on the patient CPU. If the 723 * delta exceeds UINT_MAX/2, that means it is already ahead by 724 * a little on the other CPU, and the subtraction went 725 * negative, which is OK. If the CPU's heartbeats have been 726 * suspended since we selected it, no worries. 727 * 728 * This uses the current CPU to ensure the other CPU has made 729 * progress, even if the other CPU's hard timer interrupt 730 * handler is stuck for some reason. 731 * 732 * XXX Maybe confirm it hasn't gone negative by more than 733 * max_period? 734 */ 735 d = uptime - atomic_load_relaxed(&patient->ci_heartbeat_uptime_cache); 736 if (__predict_false(d > period_secs) && 737 __predict_false(d < UINT_MAX/2) && 738 atomic_load_relaxed(&patient->ci_heartbeat_suspend) == 0) 739 defibrillate(patient, d); 740 } 741 742 /* 743 * heartbeat_dump() 744 * 745 * Print the heartbeat data of all CPUs. Can be called from ddb. 746 */ 747 #ifdef DDB 748 static unsigned 749 db_read_unsigned(const volatile unsigned *p) 750 { 751 unsigned x; 752 753 db_read_bytes((db_addr_t)(uintptr_t)p, sizeof(x), (char *)&x); 754 755 return x; 756 } 757 758 void 759 heartbeat_dump(void) 760 { 761 struct cpu_info *ci; 762 763 db_printf("Heartbeats:\n"); 764 for (ci = db_cpu_first(); ci != NULL; ci = db_cpu_next(ci)) { 765 db_printf("cpu%u: count %u uptime %u stamp %u suspend %u\n", 766 db_read_unsigned(&ci->ci_index), 767 db_read_unsigned(&ci->ci_heartbeat_count), 768 db_read_unsigned(&ci->ci_heartbeat_uptime_cache), 769 db_read_unsigned(&ci->ci_heartbeat_uptime_stamp), 770 db_read_unsigned(&ci->ci_heartbeat_suspend)); 771 } 772 } 773 #endif 774