Skip to content

fix(windows): 活性超时终止后不再空转 + 冒烟判据收紧(验证 d2mcpp#87) - #35

Merged
Sunrisepeak merged 2 commits into
mainfrom
fix/windows-checker-hang-hardening
Aug 1, 2026
Merged

fix(windows): 活性超时终止后不再空转 + 冒烟判据收紧(验证 d2mcpp#87)#35
Sunrisepeak merged 2 commits into
mainfrom
fix/windows-checker-hang-hardening

Conversation

@Sunrisepeak

Copy link
Copy Markdown
Member

排查「d2x checker 在 d2mcpp / Windows 10 上卡住」的反馈,以及验证
mcpp-community/d2mcpp#87
Provider 修复。

Draft: 两处 d2mcpp checkout 暂时指向 #87 的分支,用真 Windows 验证。
#87 合入后改回默认分支再合这个 PR。

排查结论:三条,按证据强度排

1. 活性超时在 Windows 上此前完全不生效(已于 2026.08.02.1 修复)

provider_idle_timeout 默认 120s 且默认开启,但 run_lines_idle
_WIN32 下曾显式回退为「无超时运行」。也就是说 Windows 上这个保护一直是空的
—— Provider 一旦卡住,checker 就永远等下去,没有超时、没有提示,只能 Ctrl-C。
这是「卡住」最强的候选解释,已在 2026.08.02.1 用 Job Object 补齐。

2. 终止之后仍可能空转(本 PR 修)

补齐之后仍有一个洞:killed 置位后唯一的出口是进程变有信号。若终止没生效
(Job 纳管被拒 / TerminateJobObject 被拒 / 进程卡在不可中断态),循环就以
50ms 一轮永远转下去 —— 防挂死的循环自己挂死。

改为两级兜底:5s 后补一次 TerminateProcess(Job 路径失败时还有救),15s 后
放弃等待、如实返回 idle_killed,退出码沿用 POSIX 分支被 KILL 时的 128+9

3. 课程侧:Windows 上每道题都判不出结果(d2mcpp#87 修)

d2mcpp 的 Provider 在 capture_stdout 里给命令尾巴接了 2>/dev/null
Windows 的 _popen 走 cmd.exe,那里没有 /dev/null,cmd 当成「重定向到
\dev\null 这个路径」,\dev 不存在于是报

The system cannot find the path specified.

并且整条 mcpp test 根本不执行。一条 JSON 都没有 → 判定链退化成「没有该
测试的记录」。对学习者而言就是:改对了也不过,怎么弄都没反应 —— 与「卡住」
难以区分。

这不是 mcpp 的问题:外层 mcpp run -p d2x/buildtools -- check 本身跑得通,
说明 mcpp 在 PATH 上(不在的话 cmd 报的是 'mcpp' is not recognized,另一句话);
只有内层带 2>/dev/null 的那条挂掉,两者唯一差别就是这个重定向。

判据收紧

Windows 的冒烟此前不要求透出编译错误(因为上面第 3 条)。#87 修好后收紧到与
linux 同档,并额外断言 cannot find the path specified 不再出现 —— 否则同样的
回归会静悄悄溜回来。

尚未处理:冷启动静默期可能被误杀

mcpp test 在整个编译期间不产出 stdout,Provider 因此对 d2x 静默。若 Windows
冷工具链下首题编译超过 120s,活性超时会误杀正常构建。linux 侧同样存在该
张力,只是更快所以没暴露。本 PR 不改这个默认值 —— 需要先拿到真实耗时数据,
本 PR 的 CI 正好会给出。

两处与「Windows 上 checker 卡住」直接相关。

1) run_lines_idle 终止之后可能永远空转
   Windows 分支里 killed 置位后,唯一的出口是 WaitForSingleObject 变有信号。
   若终止没生效(Job 纳管被拒、TerminateJobObject 被拒、进程卡在不可中断态),
   循环就以 50ms 一轮永远转下去 —— 这个循环存在的意义正是防挂死,它自己挂死
   是最糟的结局。改成两级兜底:5s 后补一次 TerminateProcess(Job 路径失败时
   还有救),15s 后放弃等待、如实返回 idle_killed,退出码沿用 POSIX 分支被
   KILL 时的 128+9。

2) Windows 冒烟判据收紧
   此前 Windows 这一档不要求透出编译错误,因为 d2mcpp 的 Provider 在
   capture_stdout 里给命令接了  —— cmd.exe 没有 /dev/null,报
   "The system cannot find the path specified." 且 mcpp test 根本不执行。
   该问题已在 mcpp-community/d2mcpp#87 修掉,这里同步收紧到与 linux 同档,
   并额外断言那句 cmd 报错不再出现,防止回归静悄悄溜回来。

TEMP:两处 d2mcpp checkout 暂时指向 #87 的分支以便在真 Windows 上验证;该 PR
合入后改回默认分支。
@Sunrisepeak

Copy link
Copy Markdown
Member Author

CI 结果:六个 job 全绿,Windows 判据已按收紧后的标准通过

windows-2022(Win10 基线)实测输出 —— mcpp test 真的跑起来了:

failed: obj/hello-mcpp.o
C:/Users/runneradmin/.mcpp/registry/.../clang++.exe @obj/hello-mcpp.o.rsp -std=c++23 ...
D:/a/d2x/d2x/d2mcpp/src/intro/tests/hello-mcpp.cpp:37:39: error: unexpected ':' in nested name specifier; did you mean '::'?
   37 |     std::cout << "hello, mcpp!" << std:endl; // 0.修复这个编译错误
1 warning and 1 error generated.

File:     src/intro/tests/hello-mcpp.cpp

对照修复前的 Windows 输出(The system cannot find the path specified. + 「没有该测试的记录」),d2mcpp#87 的 Provider 修复确认生效;cannot find the path specified 断言也没有触发。

顺带确认 2026.08.02.1 的路径修复在真机上成立:File: src/intro/tests/hello-mcpp.cpp,不再是 \src\intro\tests\hello-mcpp.cpp

冷启动耗时数据(前面提到的待观察项)

这一轮 Windows 的 checker 步骤在 180s 窗口内正常跑完并被 timeout 按预期杀掉
(exit=124),没有触发 120s 活性超时的误杀。也就是说预热过 Provider 之后,
首题编译的静默期在 CI 环境下是安全的。但这不能推广到学习者的冷机器 ——
真实冷工具链首次编译可能远超 120s。要不要给「首次构建」放宽活性超时,建议单独
开 issue 讨论,本 PR 不动默认值。

待办

合并前需要把两处 ref: sync/d2x-2026.08.02.1-mcpp-2026.8.1.1 改回默认分支
(等 d2mcpp#87 合入)。

d2mcpp#87 已合入 main:Provider 的 2>/dev/null 修好了,课程侧的 mcpp pin 也同步
到 2026.8.1.1。于是两件事可以收尾:

- 两处 d2mcpp checkout 的临时 ref 去掉,回到默认分支 —— 此后 Windows 的收紧判据
  长期守的是 d2mcpp main,回归会立刻现形。
- 两处「Align course mcpp pin」workaround 删除:它存在的唯一理由是课程钉在
  0.0.104 会撞 mcpplibs 索引下限,现在课程自己已经钉对了。
@Sunrisepeak
Sunrisepeak marked this pull request as ready for review August 1, 2026 19:22
@Sunrisepeak
Sunrisepeak merged commit 4d7fbc9 into main Aug 1, 2026
6 checks passed
@Sunrisepeak
Sunrisepeak deleted the fix/windows-checker-hang-hardening branch August 1, 2026 19:22
Sunrisepeak added a commit that referenced this pull request Aug 1, 2026
#35 的两处 Windows 修复发出去:
- run_lines_idle 终止后不再可能空转(5s 补杀 / 15s 放弃等待,退出码 128+9)
- checker 冒烟判据在 Windows 收紧到与 linux 同档(配合 d2mcpp#87 已合入)

版本三处同源(release.yml 会硬比对 d2x --version):mcpp.toml /
protocol/mcpp.toml / src/config.cppm Info::VERSION。
本地实测 d2x --version = 2026.08.02.2,e2e 五组 ALL GREEN。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant