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