Next: 2.3 Impure Model
Up: 2 Execution Environments
Previous: 2.1 Introduction
The pure execution model
is the most basic of the OSKit execution environments;
it has the following properties:
- Pure functions and components have no implicit global state.
For example, they do not define or use any global or static variables;
they only use and manipulate data passed explicitly the client.
For example, many functions in the minimal C library,
such as memcpy and strlen,
are pure by nature in that they only touch data areas
passed in parameters by the client
and have no other side-effects.
As a less trivial example,
the LMM and AMM memory manager components
include functions that maintain state across calls,
but only in explicit data structures visible to the client.
- Pure functions and components are fully reentrant and thread-safe
with respect to disjoint data sets.
For example, if the client OS uses the LMM
to manage several separate and disjoint memory pools,
then the lmm functions may be run concurrently
on two different processors in a multiprocessor system
without synchronization,
as long as each processor is manipulating
a different LMM memory pool.
This property is a natural consequence
of the fact that pure OSKit components
maintain no implicit global state.
- Pure functions and components are not reentrant or thread-safe
with respect to overlapping data sets.
For example,
just as it is not safe to make several memcpy calls
concurrently with overlapping destination buffers,
it is not safe to call LMM functions concurrently
on the same memory pool.
This is true for interrupt-style as well as thread-style concurrency:
for example, the client OS must not call an LMM function
on a particular memory pool from within an interrupt handler
if the interrupt handler might have interrupted
another LMM function call using the same memory pool.
In order to use these components
in an interruptible or multithreaded/multiprocessor environment,
the client OS must wrap them with appropriate synchronization code,
such as locking or interrupt priority management,
in order to ensure that only one call can be made at a time
for a given data set.
- Pure functions and components are not reentrant
with respect to overlapping data sets
even during callbacks from the component to the client OS.
In other words, callbacks are assumed to be atomic
as far as the component is concerned.
For example, the address map manager, AMM,
makes calls back to the client OS
to allocate and free memory
for use in maintaining the address map,
as well as to perform client-defined processing
when address map regions are split or joined together.
During the processing of one of these callbacks,
the client OS must not attempt
to make a reentrant call back into the AMM
operating on the same address map.
Figure:
Illustration of the execution model used by pure components.
Separate components, and separate instances of each component,
are fully independent and have no implicit shared global state;
therefore they can be invoked concurrently with no synchronization.
However, each individual instance of a component
(e.g., a particular LMM memory pool)
is single-threaded and non-reentrant;
the client OS must avoid concurrent calls to that instance,
as well as recursive calls to the same instance through callbacks.
Figure 2.1 illustrates the pure execution environment.
Since pure functions and components contain no implicit global state,
separate ``instances'' or uses of these components by the client
can be treated as completely independent objects:
although each individual instance of the component
is single-threaded and non-reentrant,
the client OS can manage synchronization
between independent instances of the component
in any way it chooses.
Next: 2.3 Impure Model
Up: 2 Execution Environments
Previous: 2.1 Introduction
University of Utah Flux Research Group