The currently executing thread gives up control by either terminating or executing a semWait operation. In other words, the x-kernel does not preempt threads; threads voluntarily give up control of the processor. However, because each protocol is assumed to be an independent component, protocols are written to assume that control may be given up when a higher or lower level protocol is invoked. Therefore, all protocol-protocol operations are considered to have the potential to cause a thread switch, and all data structures must be ``secured'' before calling such operations.
Although the x-kernel advocates a ``thread-per-message'' model, and it
provides primitives for blocking threads, as a general rule, threads
should not block except when waiting for a reply in an RPC-like
protocol. In most other cases, should a thread (message) not be able
to proceed, it should put the message in a protocol-dependent queue
and return. Later, another thread can pick the message up out of the
queue and continue processing it.
For example, when an incoming thread/message arrives in IP and
discovers that it is just one fragment of a larger datagram, rather
than blocking the thread and waiting for the other fragments to arrive,
the thread should insert the fragment into a reassembly buffer and
return. The thread that delivers the last fragment will then
reassemble the fragments into a single datagram and continue.
Where the x-kernel is embedded in another operating system, there
may be asynchronous threads representing device drivers or user
requests that want to enter the x-kernel. These threads must, in
general, acquire the x-kernel master lock (i.e., enter the x-kernel monitor)
with xk_master_lock before performing any x-kernel operations,
including other thread synchronization operations. (This isn't
necessary for normal x-kernel threads because threads started by evSchedule acquire the master lock automatically when they start
running.) Unless a call is explicitly documented otherwise, threads
may not make x-kernel system or library calls without holding the master
lock.
A thread acquires and releases the master x-kernel lock with the following
operations.
void xk_master_lock ( void )
void xk_master_unlock ( void )
Note that normal protocols should not use these operations. The only
place that they are meaningful is in anchor protocols, such as device
drivers and application-level interface, that have to transition
between the x-kernel and the host OS. Also note that this interface is
not part of the official x-kernel interface; it is internal to the
current implementation of the x-kernel.
Protocols should refrain from taking threads which are shepherding
outgoing messages down the protocol stack and turning them around to
accompany messages traveling up the protocol stack. Since protocols
are allowed to reverse thread direction from incoming to
outgoing, allowing turnaround from outgoing to incoming could lead to
a thread caught in a recursive loop. If an outgoing thread needs to
send a message back up, it should start a new thread to do this. The
push routine of the ethernet protocol (
/usr/xkernel/protocols/eth) has an example of how this is done.
To date, we do not have significant experience running the x-kernel on a
multiprocessor. We have introduced locking operations that are useful
in certain situations on a uniprocessor, and while these operations
might extend to an MP environment, we cannot be certain that they
will. Moreover, we certainly expect that the implementation of both
the locking and the semaphore operations will need to change in an MP
environment, even if the interface remains the same.
It should be noted that the x-kernel, as currently implemented, is
MP-safe, although probably not MP-performant. This is because all
threads executing in the x-kernel must first acquire a master lock; i.e.,
the x-kernel is currently implemented as a single monitor. Our experience
suggests, however, that this implementation is reasonably efficient
for a small number of processors.
External Threads
Thread Turnaround
Multiprocessor Support
Next: Trace Library
Up: Thread Library
Previous: Locking Operations