Background processes setting O_NONBLOCK on ttys
Stephen McKay
smckay at internode.on.net
Thu Jan 13 00:35:00 PST 2005
On Thursday, 13th January 2005, Peter Jeremy wrote:
>On Wed, 2005-Jan-12 23:54:38 +1000, Stephen McKay wrote:
>>a) Rewrite file descriptor handling in libc_r so it does not set O_NONBLOCK
>>on tty file descriptors unless it is in the foreground. I don't know how
>>hard this would be, or whether it even applies to -current with its profusion
>>of threading libraries. I'll leave this to those who believe in threading.
>
>In 4.x, threads are totally userland and rely on non-blocking I/O. If
>background tty file descriptors block on I/O, the entire process will
>block, not just the thread performing I/O. This is a major POLA violation.
Maybe yes, maybe no. The process stops with SIGTTOU. Stopped is stopped.
My view is that it's a POLA violation to allow other processes to fiddle
with non-blocking mode behind your back.
Anyway, this problem goes away if we can have O_NONBLOCK be per file
descriptor rather than per file open. Then it doesn't matter if a threaded
process changes its own copy of the tty descriptor. Until then, anyone who
wants to can protect themselves with my patch. It's working fine for me. :-)
>In 5.x and later, both kernel and userland threads exist.
I am totally lacking in info on 5.x and 6.x threading. If we can get rid
of O_NONBLOCK here (or if it's already gone), then the major problem is
solved. And my code to prevent non-blocking being set by background
processes can be committed. (Better safe than sorry.)
>>b) Add new non-blocking read() and write() call variants and use them in
>>the threading library instead of setting O_NONBLOCK.
>
>See aio_read(2), aio_write(2).
These look hard to use. I can't see how they could replace nonblocking
reads using O_NONBLOCK. Even if I add kqueue() to the mix I see problems.
By the way, I found a note about this from the author of djbdns. He has
much the same complaints I have. See http://cr.yp.to/unix/nonblock.html
>>c) Make O_NONBLOCK be per file descriptor (like FD_CLOEXEC). Thus,
>>descriptors produced from dup() (for example) would have their own O_NONBLOCK
>>flag, just as two descriptors from separate open() calls have today.
>
It might be useful to see what one of the POSIX experts think about this.
>FreeBSD, NetBSD, OpenBSD and Linux all explicitly state that dup(2)
>copies O_NONBLOCK (though Solaris 10 doesn't). It is reasonably likely
>that existing code relies on the documented behaviour and will therefore
>break when you move O_NONBLOCK from the file to the file descriptor.
You can still have dup() copy the O_NONBLOCK flag. That's probably sensible.
But if you did "b = dup(a)" then changed the O_NONBLOCK flag on "b" you
wouldn't see that reflected on "a" (unlike now).
Even after sleeping on this, I think option c) is the right answer.
Stephen.
More information about the freebsd-hackers
mailing list