mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-11-06 17:27:31 +00:00
refactor(agent/core): 中断队列归还调度器,中断管理器只留现场保护
用户裁定:「中断队列就该调度器管理啊,中断管理器只负责进入中断的任务」。 上一版我把 interruptQueues/immediate 也搬进了中断管理器,这是错的: 排队是**调度职责**——判断该不该打断、打断不了先排队、按什么次序再取出来, 全是调度策略,不是"进入中断"本身。 ## 本次改动 中断管理器(interrupt.go)现在只有: - 中断栈 suspendStack(**唯一操作者**:压栈/弹栈都在其内) - 中断屏蔽 critical(对应 CPU 关中断) - 让位信号原语 preemptArmed/preemptLevel - 栈状态钩子 stackNotify 迁回调度器(scheduler.go): - interruptQueues[5] / immediate 两个字段 - highestInterruptLocked / popInterruptLocked / interruptCountLocked - enqueueInterruptLocked / installImmediateLocked ## 新增边界判据 TestInvariant_InterruptManagerHoldsOnlyStackState 用**反射白名单**钉住边界: interruptState 只允许 6 个字段(栈/屏蔽/让位×2/上界/钩子)。 反向确认 interruptQueues 与 immediate 确实在 scheduler 上——避免"两边都没有"的假绿。 变异验证:把 interruptQueues 塞回 interruptState ⇒ 判据立刻变红 ("中断管理器不应持有这些字段:[interruptQueues]")。 ## 验证 - go build ./... 通过 - go test ./internal/agent/core/ 通过 - go test -race ./internal/agent/core/ 通过 - 12 条不变量判据全绿 ## 顺带排查:/tmp 是 tmpfs 且已 91% `df` 显示 /tmp 是 8.8G tmpfs,Go 链接期临时文件把它填满, 导致并发构建出现 write ... no space left on device(表现为 某包 `FAIL 0.008s`——不是代码问题)。已改用 TMPDIR=/var/tmp/gobuild(根分区 112G)。
This commit is contained in:
@ -21,6 +21,7 @@ package core
|
||||
// 否则搬完只能靠"看起来还对"来判断,而这类不变量恰恰是肉眼看不出的。
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
agentIO "github.com/JianFeeeee/HologramAgent/internal/agent/io"
|
||||
@ -224,6 +225,45 @@ func TestInvariant_SuspendedEqualsResumed(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// ── I0:边界不变量 —— 队列归调度器,中断管理器只管现场保护 ──
|
||||
|
||||
// 用户栽定:「中断管理器只负责进入中断和中断栈的部分」、
|
||||
// 「中断队列就该调度器管理」。
|
||||
//
|
||||
// 这条判据用**结构事实**钉住边界,而不是靠注释:
|
||||
// interruptState 里只允许出现现场保护/屏蔽相关字段;
|
||||
// 一旦有人把队列或优先级策略塞回来,这里立刻变红。
|
||||
func TestInvariant_InterruptManagerHoldsOnlyStackState(t *testing.T) {
|
||||
// 反射枚举 interruptState 的字段名,白名单校验。
|
||||
typ := reflect.TypeOf(interruptState{})
|
||||
allowed := map[string]bool{
|
||||
"suspendStack": true, // 中断栈
|
||||
"critical": true, // 中断屏蔽
|
||||
"preemptArmed": true, // 让位信号
|
||||
"preemptLevel": true, // 让位信号
|
||||
"maxInterruptFrames": true, // 栈上界
|
||||
"stackNotify": true, // 栈状态钩子
|
||||
}
|
||||
var bad []string
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
name := typ.Field(i).Name
|
||||
if !allowed[name] {
|
||||
bad = append(bad, name)
|
||||
}
|
||||
}
|
||||
if len(bad) > 0 {
|
||||
t.Fatalf("中断管理器不应持有这些字段(队列/优先级归调度器): %v", bad)
|
||||
}
|
||||
|
||||
// 反向确认:队列确实在 scheduler 上(而不是"两边都没有"的假绿)。
|
||||
st := reflect.TypeOf(scheduler{})
|
||||
for _, want := range []string{"interruptQueues", "immediate"} {
|
||||
if _, ok := st.FieldByName(want); !ok {
|
||||
t.Fatalf("中断队列 %s 应在 scheduler 上(排队是调度职责)", want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── I7:中断栈状态钩子必须被接上,且栈变化会通告 ──
|
||||
|
||||
// 中断管理器与调度器唯一的联系就是这个钩子。它若为空,栈的压入/弹出
|
||||
|
||||
Reference in New Issue
Block a user