上面的结构完美符合我们最初的场景: p1 是操作系统的 1 号进程 init,p2 是 bash shell,p3 是 strace(ctrl-c 之后进程死掉),p4 是 python repl。这个结构恐怕很难简化,如果有哪位老师发现 3 进程可以复现请教教我
#!/usr/bin/env python3
import os, sys, pty, fcntl, termios, signal, time

def handler(sig, f):
    pass

def spawn_p2():
    master_fd, slave_fd = pty.openpty()
    os.setsid()
    fcntl.ioctl(slave_fd, termios.TIOCSCTTY, 0)

    p2_pgid = os.getpgrp()

    pid3 = os.fork()
    if pid3 == 0:
        os.setpgid(0, 0)
        os.dup2(slave_fd, 0)
        os.dup2(slave_fd, 1)
        os.dup2(slave_fd, 2)
        if slave_fd > 2:
            os.close(slave_fd)
        pid4 = os.fork()
        if pid4 == 0:
            signal.signal(signal.SIGTTOU, handler)
            exe = 'python'
            os.execlp(exe, os.path.basename(exe))
        else:
            os.tcsetpgrp(0, p2_pgid)
            os._exit(0)

    try:
        os.setpgid(pid3, pid3)
    except ProcessLookupError:
        pass

    os.tcsetpgrp(slave_fd, pid3)

    if slave_fd > 2:
        os.close(slave_fd)

    os.waitpid(pid3, 0)
    time.sleep(1)

    os.tcsetpgrp(master_fd, p2_pgid)

    while 1:
        os.read(master_fd, 1024)

def main():
    pid2 = os.fork()
    if pid2 == 0:
        spawn_p2()
    else:
        time.sleep(1 << 30)

if __name__ == "__main__":
    main()

运行 docker run --name repl -td -v $(pwd):/src python:3.14.0rc2 python /src/main.py,观察到下面的进程树。
root       67924   67901  1 13:49 pts/0    00:00:00  \_ python /src/orp_repl2.py
root       67977   67924  1 13:49 pts/1    00:00:00      \_ python /src/orp_repl2.py
root       67979   67924 79 13:49 pts/1    00:00:02      \_ python


strace -p 最新的 python 进程,确认无限 EIO,QED
 
 
Back to Top