Subject: Re: Time to fix a 25 year old misdesign
To: NetBSD Kernel Technical Discussion List <tech-kern@NetBSD.ORG>
From: Greg A. Woods <email@example.com>
Date: 10/17/2000 02:03:03
[ On Tuesday, October 17, 2000 at 05:33:28 (+0200), Lennart Augustsson wrote: ]
> Subject: Re: Time to fix a 25 year old misdesign
> But now you are solving the SIGIO problem by adding two special purpose
> driver methods.
Well, sort of -- I don't think my proposal is correct, but rather just
one of the crazy ways of "fixing" SIGIO. I suspect the current places
where SIGIO is "broken" are the fault of subsequent implementors
misunderstanding its role.
In fact the more I look at SIGIO the more I believe it is not very well
thought out at all. I've not knowingly ever used it before and I've
always wondered just what problems it can solve that select()/poll()
> I also want to add methods too, but they have other uses as well.
> I don't think I'm just partly right, I think I'm right. :)
Hmm.... yes, I forgot about fork() allowing multiple processes to access
the same file file, exclusive access or not. I suppose descriptor
passing and dup() would also cause multiple references, though until a
fork() occurs only the former will lead to trouble on this front.
Hardware drivers really do not have any business sending SIGIO directly!
> But since a process can register to get a SIGIO and then die it is broken.
Ah, but your code doesn't actually register to get a SIGIO -- it just
sets up a handler!
That it works must be due to a 4.3BSD braid-dead-ism.
The proper way to register interest in asynchronous I/O events is to
call fcntl(fd, F_SETOWN, getpid()) and then fcntl(fd, F_SETFL, O_ASYNC)
[of course you should use F_GETFL and binary-OR in the O_ASYNC flag].
Since processes on BSD ignore SIGIO by default it is apparently not
generally considered a problem if an unprivileged process registers
O_ASYNC for an unrelated process [fcntl(F_SETOWN) doesn't return EACCESS
if the process is unrelated], or sends it unconditionally to an
unrelated process as your test programs do. [We'll probably learn too
late of ways to cause trouble because of this! ;-)]
> And the brokenness comes from the fact that since there are multiple
> references to the file descriptor the death of the process is not the last
> close so the driver is not notified.
The real brokenness comes from the fact that the driver records the
"struct proc *" when it has no real business doing any such thing -- the
driver really shouldn't look that closely at who called it.
I do note from reading McKusick that SIGIO is implemented in the TTY
subsystem by sending SIGIO to the entire process group and thus the
low-level hardware driver need not know anything about what processes
have the terminal open, and by examination we can see that serial
hardware drivers, such as sys/dev/ic/com.c, do not send SIGIO directly
Perhaps other classes of character drivers, such as audio, should have a
similar upper layer to handle O_ASYNC and do the reference accounting up
where open(2) and close(2) calls are symmetric and associated directly
with individual processes and actual file descriptors, and not try to do
this kind of thing deep in the driver guts where file descriptors are
essentially unheard of. I suspect there's a very good reason after all
why SIGIO is enabled via fcntl(2) and not ioctl(2)!
In the end though I think SIGIO should probably die. I think it's
completely the wrong approach to trying to multi-thread an application
with asynchronous IO. As Stevens says I/O multiplexing [with
select() or poll()] is a far better technique, never mind the
restrictions SIGIO imposes on the types of files it works with, and the
inability for it to identify which descriptor has pending I/O, and the
expense of catching signals, etc....
 The Design and Implementation of the 4.4BSD Operating System
M.K.McKusick et al.
 Advanced Programming in the UNIX Environment
W. Richard Stevens
Greg A. Woods
+1 416 218-0098 VE3TCP <firstname.lastname@example.org> <robohack!woods>
Planix, Inc. <email@example.com>; Secrets of the Weird <firstname.lastname@example.org>