fix(v4): the kernel's fatal stops halt, interrupts off, instead of spinning (#177)
sk_v4_run's three stops -- "not started", "did not let go of POST's
blocks", "stopped on a fault" -- ended in for (;;) { }: a core spinning at
100%, the thing #151 removed from the prompt. Each now calls sk_v4_stop()
(kernel/src/v4/sk_v4_stop.c): interrupts off, then arch_halt() for ever. Each
still says why first. sk_v4_stop.c added to the loader's and the kernel's v4
sources.
kernel/tests/test_sk_v4_stop.c, with arch_halt and arch_disable_interrupts
faked (the halt jumps back out after three calls; an alarm fails a spin):
against the stop as it was -- "spun for 2 s without halting"; now -- 2
checks, 0 failures: halts in a loop, interrupts off before the first halt.
Built for amd64, aarch64 and riscv64. #177's "seen on the three
architectures": no boot reaches these stops, so it is shown on the host only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
This commit is contained in:
+2
-2
@@ -730,8 +730,8 @@ V4_ENGINE_SRCS := $(addprefix v4/src/,node.c exec.c stack.c iword.c heat.c guard
|
||||
V4_ROM_C := $(BUILD_DIR)/v4_rom_64.c
|
||||
V4_MAP_C := $(BUILD_DIR)/v4_map_64.c
|
||||
|
||||
LOADER_EXTRA_SRCS += $(KERNEL_SRC)/v4/sk_v4.c $(KERNEL_SRC)/v4/sk_v4_identity.c $(KERNEL_SRC)/v4/sk_v4_marker.c $(KERNEL_SRC)/v4/sk_v4_grow.c $(KERNEL_SRC)/v4/sk_v4_mint.c
|
||||
KERNEL_EXTRA_SRCS += $(KERNEL_SRC)/v4/sk_v4.c $(KERNEL_SRC)/v4/sk_v4_identity.c $(KERNEL_SRC)/v4/sk_v4_marker.c $(KERNEL_SRC)/v4/sk_v4_grow.c $(KERNEL_SRC)/v4/sk_v4_mint.c
|
||||
LOADER_EXTRA_SRCS += $(KERNEL_SRC)/v4/sk_v4.c $(KERNEL_SRC)/v4/sk_v4_identity.c $(KERNEL_SRC)/v4/sk_v4_marker.c $(KERNEL_SRC)/v4/sk_v4_grow.c $(KERNEL_SRC)/v4/sk_v4_mint.c $(KERNEL_SRC)/v4/sk_v4_stop.c
|
||||
KERNEL_EXTRA_SRCS += $(KERNEL_SRC)/v4/sk_v4.c $(KERNEL_SRC)/v4/sk_v4_identity.c $(KERNEL_SRC)/v4/sk_v4_marker.c $(KERNEL_SRC)/v4/sk_v4_grow.c $(KERNEL_SRC)/v4/sk_v4_mint.c $(KERNEL_SRC)/v4/sk_v4_stop.c
|
||||
# v4/system/boot.c is the boot the hosted v4 system runs too: the ROM
|
||||
# assembles the system, then the capsules from this kernel's own capsule
|
||||
# directory, then the prompt.
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/* SPDX-License-Identifier: LicenseRef-Starship-1.0
|
||||
* Copyright (c) 2023-2026 Robert A. James
|
||||
*/
|
||||
/* sk_v4_stop.h -- the v4 kernel's fatal stop (#177): what sk_v4_run does when the system cannot
|
||||
* go on ("not started", "did not let go of POST's blocks", "stopped on a fault"). Never returns.
|
||||
*/
|
||||
#ifndef STARKERNEL_V4_SK_V4_STOP_H
|
||||
#define STARKERNEL_V4_SK_V4_STOP_H
|
||||
|
||||
void sk_v4_stop(void) __attribute__((noreturn));
|
||||
|
||||
#endif
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "starkernel/v4/sk_v4_mint.h"
|
||||
#include "starkernel/v4/sk_v4.h"
|
||||
#include "starkernel/v4/sk_v4_identity.h"
|
||||
#include "starkernel/v4/sk_v4_stop.h"
|
||||
#include "starkernel/kbd_input.h"
|
||||
#include "starkernel/console.h"
|
||||
#include "starkernel/arch.h"
|
||||
@@ -159,7 +160,7 @@ void sk_v4_run(void (*chain)(void), const BootDisk *boot_disk)
|
||||
blk_subsys_init(sk_v4_post_blk_ram, sizeof(sk_v4_post_blk_ram));
|
||||
if (!v4_boot_run(&boot)) {
|
||||
console_println("StarForth v4: not started");
|
||||
for (;;) { }
|
||||
sk_v4_stop(); /* #177: halts, not a 100% spin */
|
||||
}
|
||||
if (chain) {
|
||||
/* the blocks are other blocks now: what the node has in its two
|
||||
@@ -167,7 +168,7 @@ void sk_v4_run(void (*chain)(void), const BootDisk *boot_disk)
|
||||
chain();
|
||||
if (v4_boot_line(&boot, "EMPTY-BUFFERS", 13) != V4_TEXT_COMPLETED) {
|
||||
console_println("StarForth v4: the node did not let go of POST's blocks");
|
||||
for (;;) { }
|
||||
sk_v4_stop(); /* #177: halts, not a 100% spin */
|
||||
}
|
||||
}
|
||||
sk_v4_identity_boot(boot_disk);
|
||||
@@ -230,7 +231,7 @@ void sk_v4_run(void (*chain)(void), const BootDisk *boot_disk)
|
||||
else if (how == V4_BOOT_LINE_REFUSED) console_puts("Message refused\n ERROR\n"); /* the node's wire is full: error 19's words */
|
||||
else if (how == V4_BOOT_LINE_STOPPED) {
|
||||
console_println("StarForth v4: the node stopped on a fault");
|
||||
for (;;) { }
|
||||
sk_v4_stop(); /* #177: halts, not a 100% spin */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/* SPDX-License-Identifier: LicenseRef-Starship-1.0
|
||||
* Copyright (c) 2023-2026 Robert A. James
|
||||
*/
|
||||
/* sk_v4_stop.c -- see sk_v4_stop.h. */
|
||||
#include "starkernel/v4/sk_v4_stop.h"
|
||||
#include "starkernel/arch.h"
|
||||
|
||||
/* Interrupts off, then halt for ever: the core sleeps instead of spinning at 100% (#177), and no
|
||||
* timer or device wakes it to do anything. sk_v4_run's three stops each said why first. */
|
||||
void sk_v4_stop(void)
|
||||
{
|
||||
arch_disable_interrupts();
|
||||
for (;;) arch_halt();
|
||||
}
|
||||
@@ -19,7 +19,8 @@ CC ?= cc
|
||||
CFLAGS := -std=c99 -Wall -Wextra -Werror -O2 -g -I$(HERE) -I$(ROOT)/kernel/include \
|
||||
-I$(ROOT)/kernel/include/starkernel -I$(ROOT)/v3/include
|
||||
|
||||
TESTS := test_gpt test_usb_config
|
||||
TESTS := test_gpt test_usb_config test_sk_v4_stop
|
||||
SRC_test_sk_v4_stop := $(ROOT)/kernel/src/v4/sk_v4_stop.c
|
||||
SRC_test_gpt := $(ROOT)/kernel/src/gpt.c
|
||||
SRC_test_usb_config := $(ROOT)/kernel/src/usb/usb_config.c
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/* SPDX-License-Identifier: LicenseRef-Starship-1.0
|
||||
* Copyright (c) 2023-2026 Robert A. James
|
||||
*/
|
||||
/* test_sk_v4_stop.c -- kernel/src/v4/sk_v4_stop.c on the host (#177): the v4 kernel's fatal stops
|
||||
* halt -- interrupts off, then arch_halt() in a loop -- instead of spinning a core at 100%.
|
||||
* arch_halt() and arch_disable_interrupts() are faked: the fake halt counts, and after a few calls
|
||||
* jumps back out of the loop. A stop that spins never calls it: an alarm ends the test as failed.
|
||||
*/
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include "harness.h"
|
||||
#include "starkernel/v4/sk_v4_stop.h"
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static jmp_buf out;
|
||||
static int halts, irq_off, irq_off_before_first_halt = -1;
|
||||
|
||||
void arch_disable_interrupts(void) { irq_off = 1; }
|
||||
void arch_enable_interrupts(void) { irq_off = 0; }
|
||||
void arch_halt(void)
|
||||
{
|
||||
if (irq_off_before_first_halt < 0) irq_off_before_first_halt = irq_off;
|
||||
if (++halts >= 3) longjmp(out, 1); /* it is halting, again and again: enough */
|
||||
}
|
||||
static void spun(int sig)
|
||||
{
|
||||
(void)sig;
|
||||
static const char msg[] = "FAIL sk_v4_stop spun for 2 s without halting (#177)\n 1 checks, 1 failures\n";
|
||||
(void)!write(1, msg, sizeof msg - 1); /* not printf: _exit would not flush it */
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
signal(SIGALRM, spun);
|
||||
alarm(2);
|
||||
if (setjmp(out) == 0) sk_v4_stop();
|
||||
alarm(0);
|
||||
CHECK(halts == 3, "#177: the stop halts in a loop (arch_halt called %d times before the test stopped it)", halts);
|
||||
CHECK(irq_off_before_first_halt == 1, "#177: interrupts off before the first halt, so nothing wakes it to spin again");
|
||||
return DONE();
|
||||
}
|
||||
Reference in New Issue
Block a user