Hi, When I tested my "tty.py" example with my patch to support TTY in UNIX write pipe transport, I found an issue with cat.
With "cat | python3 examples/tty.py", cat fails with "cat: -: Resource temporarily unavailable". It looks like setting the O_NONBLOCK flag on a TTY affects two separated processes (cat and python). I wrote two programs to try to understand. Output of tty_blocking.py: --- stdin: FD 0 stdout: FD 1 stderr: FD 2 stdin and stdout are the same device? True stdout and stderr are the same device? True stdin: blocking stdout: blocking stderr: blocking set stdout to non-blocking stdin: non-blocking stdout: non-blocking stderr: non-blocking --- So setting the non-blocking mode of stdout affects also stdin and stderr. Output of "python3 tty_stat.py|python3 tty_stat.py": --- [10701] stdin: TTY? True, device 11.5 [10702] stdin: TTY? False, device 8.60938304 [10701] stdout: TTY? False, device 8.60938304 [10702] stdout: TTY? True, device 11.5 --- As expected, the stdin of the reader is connected to the stdout of the writer: it's the pipe 8.60938304. But the stdin of the reader and the stdout of the writer are the same TTY: device 11.5. Setting the O_NONBLOCK flag on a TTY affects all processes. asyncio should not do that, but it means that os.read() or os.write() might block!? Victor
import fcntl import os import os.path import sys stdin = sys.stdin.fileno() stdout = sys.stdout.fileno() stderr = sys.stderr.fileno() def get_nonblocking(fd): flags = fcntl.fcntl(fd, fcntl.F_GETFL) return "non-blocking" if flags & os.O_NONBLOCK else "blocking" def set_nonblocking(fd): flags = fcntl.fcntl(fd, fcntl.F_GETFL) flags = flags | os.O_NONBLOCK fcntl.fcntl(fd, fcntl.F_SETFL, flags) def dump_state(): print("stdin: %s" % get_nonblocking(stdin)) print("stdout: %s" % get_nonblocking(stdout)) print("stderr: %s" % get_nonblocking(stderr)) print("") print("stdin: FD %s" % stdin) print("stdout: FD %s" % stdout) print("stderr: FD %s" % stderr) print("") print("stdin and stdout are the same device? %s" % os.path.samestat(os.fstat(stdin), os.fstat(stdout))) print("stdout and stderr are the same device? %s" % os.path.samestat(os.fstat(stdout), os.fstat(stderr))) print("") dump_state() print("set stdout to non-blocking") print("") set_nonblocking(stdout) dump_state()
import os import sys pid = os.getpid() stdin = os.fstat(0) stdin_tty = os.isatty(0) stdout = os.fstat(1) stdout_tty = os.isatty(1) print("[%s] stdin: TTY? %s, device %s.%s" % (pid, stdin_tty, stdin.st_dev, stdin.st_ino), file=sys.stderr) print("[%s] stdout: TTY? %s, device %s.%s" % (pid, stdout_tty, stdout.st_dev, stdout.st_ino), file=sys.stderr)