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)

Reply via email to