Next: Part II: Interfaces
Up: 2.5 Interruptible Blocking Model
Previous: 2.5.3 Use in multiple-interrupt-level
Many small kernels use a pure interrupt model internally
rather than a traditional process model;
this basically means that there is only one kernel stack per processor
rather than one kernel stack per process,
and therefore kernel code can't block
without losing all of the state on its stack.
This is probably the most difficult environment
in which to use the framework,
since the framework fundamentally assumes
one stack per outstanding component invocation.
Nevertheless, there are a number of reasonable ways
to work around this mismatch of execution model,
some of which are described briefly below as examples:
- Switch stacks while running driver code.
Before the kernel invokes a component operation
(e.g., makes a read or write request),
it allocates a special ``alternate'' kernel stack,
possibly from a ``pool'' of stacks reserved for this purpose.
This alternate stack is associated with the outstanding operation
until the operation completes;
the kernel switches to the alternate stack
before executing process-level component code,
and switches back to the per-processor kernel stack
when the driver blocks or returns.
Depending on the details of the kernel's execution model,
the kernel may also have to switch back to the per-processor stack
when the process-level component code is interrupted,
due to an event such as a hardware interrupt
or a page fault occurring while copying data
into or out of a user-mode process's address space.
However, note that stack switching is only required
when running process-level component code;
interrupt handlers in this execution model
are already ``interrupt model'' code and need no special adaptation.
- Run process-level device driver code on a separate kernel thread.
If the kernel supports kernel threads in some form
(threads that run using a traditional process model
but happen to execute in the kernel's address space),
then process-level component code can be run on a kernel thread.
Basically, the kernel creates or otherwise ``fires off''
a new kernel thread for each new component operation invoked,
and the thread terminates when the operation is complete.
(If thread creation and termination are expensive,
then a ``pool'' of available threads can be cached.)
The kernel must ensure that the threads
active in a particular component at a given time
cannot preempt each other arbitrarily except
in the blocking functions defined by this framework;
one way to do this is with locks (see Section 2.5.2).
Conceptually, this solution is more or less isomorphic
to the stack switching solution described above,
since a context switch basically amounts to a stack switch;
only the low-level details are really different.
- Run the device drivers in user mode.
If a process-model environment cannot easily
be provided or simulated within the kernel,
then the best solution may be
to run components in user mode,
as ordinary threads running on top of the kernel.
Of course, this solution brings with it
various potential complications and efficiency problems;
however, in practice they may be fairly easily surmountable,
especially in kernels that already support
other kinds of user-level OS components
such as device drivers, file systems, etc.
- Run the device drivers at an intermediate privilege level.
Some processor architectures, such as the x86 and PA-RISC,
support multiple privilege levels
besides just ``supervisor mode'' and ``user mode.''
Kernels for such architectures
may want to run blocking OSKit components under this framework
at an intermediate privilege level,
if this approach results in a net win
in terms of performance or implementation complexity.
Alternatively, on most architectures,
the kernel may be able to run blocking OSKit components
in user mode but with an address map identical to the kernel's,
allowing them direct access to physical memory
and other important kernel resources.
Next: Part II: Interfaces
Up: 2.5 Interruptible Blocking Model
Previous: 2.5.3 Use in multiple-interrupt-level
University of Utah Flux Research Group