BSD has processes with a proc structure. When a process makes a system call that can block (such as accept), it will call sleep (or tsleep). When an event happens that will allow the process to unblock, the kernel calls "wakeup" to set it going. When blocked it is on some sleep queue, when unblocked it is on some run queue. The details of the run queue is of no importance here. A call to sleep looks like this:
sleep(iorq, PRIBIO); err = tsleep(&so->so_timeo, PSOCK | PCATCH, netcon, 0) wakeup(iorq);The code that implements these is in kern_synch.c
The call to sleep never returns an error.
The first argument is the "ident" or sleep address,
the second address is a priority.
The call to tsleep is more commonly used (or so it seems). The first two arguments are the same as sleep, the third is a string argument that shows (in 2 characters) what sort of sleep is going on. The last argument is a time in counts of HZ. A timeout of 0 is no timeout (just like a sleep call, but with the option to specify the string). If the tsleep is awakened by wakeup, the return is 0. If the tsleep times out, the return is EWOULDBLOCK in most cases, but perhaps other things when signals are involved.
Both accept and connect sleep on &so->so_timeo.
soclose() sleeps on this channel also.
Wakeups on this channel happen in:
soisconnected(so) soisdisconnecting(so) soisdisconnected(so) sonewconn1(head, connstatus) tcp_notify(inp, error) in tcp_subr.cEach call to tsleep is wrapped in a test loop. Note however that the wait channel includes the specific socket structure address, so the wakeup will only affect the process waiting on that specific socket.
For connect, The call is:
while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH, netcon, 0);For accept, it is:
while (so->so_qlen == 0 && so->so_error == 0) error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH, netcon, 0);Note that in both these cases the timeout argument is 0 (so it sleeps forever). The loop is typical and essential. In unix there may be a number of processes sleeping on the same event. The wakeup will wake them all up and they must check the condition and go back to sleep if it is still pending.
wakeup((caddr_t) &so->so_timeo); gets called by notify when errors occur.
Kyu / [email protected]