From: Paul Ruizendaal
It would not seem terribly complex to add non-blocking
i/o capability to
V6. ... Adding a 'capacity' field to the sgtty interface would not
have been a big leap either. ...
Maybe in the 1975-1980 time frame this was not felt to be 'how Unix does
it'?
This point interested me, so I went and had a look at how the MIT V6+/PWB
TCP/IP did it. I looked at user TELNET, which should be pretty simple (server
would probably be more complicated, due to PTY stuff).
It's totally different - although that's in part because in the MIT system,
TCP is in the user process, along with the application. In the user process,
there's a common non-premptive 'tasking' package which both the TCP and
TELNET
code use. When there are no tasks ready to run, the process uses the sleep()
system call to wait for a fixed, limited quantum (interrupts, i.e. signals,
will usually wake it before the quantum runs out); note this comment:
/ uses the system sleep call rather than the standard C library
/ sleep (sleep (III)) because there is a critical race in the
/ C library implementation which could result in the process
/ pausing forever. This is a horrible bug in the UNIX process
/ control mechanism.
Quoted without comment from me!
There are 3 TCP tasks - send, receive and timer. The process receives an
'asynchronous I/O complete' signal when a packet arrives, and that wakes up
the process, and then one of the tasks therein, to do packet processing
(incoming data, acks, etc).
There appears to be a single TELNET task, which reads from the user's
keyboard, and sends data to the network. (It looks like processing of incoming
data is handled in the context of one of the TCP tasks.) Its main loop starts
with this:
ioctl (0, FIONREAD, &nch);
if (nch == 0) {
tk_yield ();
continue;
}
}
if ((c = getchar()) == EOF) {
so that ioctl() must look to see if there is any data waiting in the terminal
input buffer (I'm too lazy to go see what FIONREAD does, right at the moment).
Noel