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)