复位命令必须带 timeout:实测它自己会永久挂住,还留下占着 USB 的僵尸进程

上一版把触觉 wedged 的处置改成「首选 `sudo -n orisys-usb-reset`(免密,无人值守
可直接跑)」。真跑了一次,发现这句话是错的:

    sudo -n /usr/local/bin/orisys-usb-reset 1-3.4.1

跑了 **155s 都没返回**,进程停在 `S` 状态(卡在写
`/sys/bus/usb/drivers/usb/unbind`),`timeout 90` 都收不掉它 —— 现场留下了三个
残留进程。对无人值守来说这是最坏的结果:那一轮在这里永久卡死,而且这个进程还
占着 USB,后面重试触觉只会继续失败。

复位之后 `1-3.4.1` 直接从 sysfs **消失**了(复位前它还在总线上、只是没有
/dev/video*)—— 也就是设备比复位前掉得更彻底。所以这条命令**不是**"跑一下试试"
那种安全操作,必须当有副作用的操作对待。

改动:
· 两处给现场的命令一律写成 `timeout 15 sudo -n /usr/local/bin/orisys-usb-reset
  <devpath>`,并把「不加 timeout 会永久卡住 + 留僵尸进程」写进提示原文。
  这与 `orisys_tactile.py` 的自动自愈口径一致(那里本来就是 `timeout=15.0`,
  所以自动路径不受影响,只有手工执行的建议是错的)。
· 复位后设备仍不在总线上(或消失)→ 明确归到**物理**处置:拔插该相机 /
  给这个 Hub 断电重启。

测试:test_v4l_health 新增两条 —— 断言给出的复位命令里含 `timeout 15`,
以及提示里必须写出"会挂住"这件事(只给命令不说风险,人就会裸跑它)。
全仓库 1119 passed / 1 skipped。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
arm_dev
2026-09-28 10:46:06 +08:00
parent 02c26cfb86
commit bb6f792922
3 changed files with 32 additions and 6 deletions
@@ -84,6 +84,18 @@ def test_check_devices_reports_wedged_for_the_real_failure(tmp_path: Path) -> No
assert c.level == "error"
assert "orisys-usb-reset 1-3.4.1" in c.text(), "必须给出可直接执行的复位命令"
assert "拔插" in c.text(), "也要给出不需要 root 的办法"
# 复位命令必须带 timeout:2026-09-28 实测这一句会卡在写 unbind 上 155s 不返回,
# 无人值守的那一轮会永久卡住、还留下一个占着 USB 的僵尸进程。
assert "timeout 15 sudo -n" in c.text(), "给出的复位命令必须是有界的"
def test_wedged_hint_says_the_reset_can_hang() -> None:
"""复位会挂住这件事必须写在提示里 —— 只给命令不说这件事,人就会裸跑它。"""
import v4l_health
text = v4l_health.Check("左指", LEFT_BY_PATH, "1-3.4.1", "wedged", []).text()
assert "unbind" in text or "卡住" in text
assert "僵尸" in text or "永久" in text
def test_check_devices_reports_unplugged_when_device_is_gone(tmp_path: Path) -> None: