Files
Robot_Arm/ml/selftest_proc.py
T

72 lines
3.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""本机自检的进程部分(2026-10-18 第七轮,遗留 C-5:Windows 生命周期从未实测)。由 ml/selftest.sh 调用。
tree :按控制台同一套标志(Windows: CREATE_NEW_PROCESS_GROUP|CREATE_NO_WINDOW;POSIX: 新会话)起 bash → python + node 两个孙进程,
再用控制台同一套停止方法(Windows: taskkill /T /F;POSIX: 按会话 TERM)结束,检查孙进程是否全部消失。
detach :起一个"启动器"进程,它按同一标志拉起子树后立刻退出,检查子树是否还活着(等价于关掉控制台黑窗口后训练是否继续)。
输出一行 JSON:{"tree_killed": bool, "survive_parent_exit": bool, ...}"""
import json, os, subprocess, sys, time, tempfile, shutil
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, ROOT)
from ml.monitor import find_bash, kill_session # noqa: E402
FLAGS = {'creationflags': subprocess.CREATE_NEW_PROCESS_GROUP | 0x08000000} if os.name == 'nt' else {'start_new_session': True}
def alive(pid):
if os.name == 'nt':
r = subprocess.run(['tasklist', '/FI', f'PID eq {pid}', '/NH'], capture_output=True, text=True)
return str(pid) in r.stdout
try: os.kill(pid, 0); return True
except OSError: return False
def tree_cmd(d):
py = sys.executable.replace('\\', '/'); dd = d.replace('\\', '/')
return (f'"{py}" -c "import os,time;open(\'{dd}/p.pid\',\'w\').write(str(os.getpid()));time.sleep(300)" & '
f'node -e "require(\'fs\').writeFileSync(\'{dd}/n.pid\',String(process.pid));setInterval(()=>{{}},1000)" & wait')
def wait_pids(d, t=20):
for _ in range(t * 4):
try: return int(open(os.path.join(d, 'p.pid')).read()), int(open(os.path.join(d, 'n.pid')).read())
except Exception: time.sleep(0.25)
return None, None
def main():
bash = find_bash(); out = {'os': os.name, 'bash': bash}
if not bash: out['error'] = '找不到 bash'; print(json.dumps(out, ensure_ascii=False)); return
# tree
d = tempfile.mkdtemp(prefix='st_tree_')
p = subprocess.Popen([bash, '-c', tree_cmd(d)], stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, **FLAGS)
pp, pn = wait_pids(d)
out['tree_started'] = pp is not None and pn is not None
if out['tree_started']:
if os.name == 'nt': subprocess.run(['taskkill', '/T', '/F', '/PID', str(p.pid)], capture_output=True)
else: kill_session(p.pid)
time.sleep(3)
out['tree_left'] = {'python': alive(pp), 'node': alive(pn)}
out['tree_killed'] = not any(out['tree_left'].values())
for x in (pp, pn): # 清场
if alive(x):
if os.name == 'nt': subprocess.run(['taskkill', '/F', '/PID', str(x)], capture_output=True)
else: os.kill(x, 9)
shutil.rmtree(d, ignore_errors=True)
# detach:启动器拉起子树后立即退出
d = tempfile.mkdtemp(prefix='st_det_')
launcher = ('import subprocess,sys;' f'f={FLAGS!r};' 'subprocess.Popen([sys.argv[1],"-c",sys.argv[2]],stdin=subprocess.DEVNULL,stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL,**f)')
subprocess.run([sys.executable, '-c', launcher, bash, tree_cmd(d)], timeout=30)
pp, pn = wait_pids(d)
time.sleep(3)
out['survive_parent_exit'] = bool(pp and pn and alive(pp) and alive(pn))
for x in (pp, pn):
if x and alive(x):
if os.name == 'nt': subprocess.run(['taskkill', '/F', '/PID', str(x)], capture_output=True)
else: os.kill(x, 9)
shutil.rmtree(d, ignore_errors=True)
print(json.dumps(out, ensure_ascii=False))
if __name__ == '__main__':
main()