osd-contiki/doc/pt-doc.txt

178 lines
No EOL
7.1 KiB
Text

/**
\addtogroup sys
@{
*/
/**
\defgroup pt Protothreads
Protothreads are a type of lightweight stackless threads designed for
severly memory constrained systems such as deeply embedded systems or
sensor network nodes. Protothreads provides linear code execution for
event-driven systems implemented in C. Protothreads can be used with
or without an RTOS.
Protothreads are a extremely lightweight, stackless type of threads
that provides a blocking context on top of an event-driven system,
without the overhead of per-thread stacks. The purpose of protothreads
is to implement sequential flow of control without complex state
machines or full multi-threading. Protothreads provides conditional
blocking inside C functions.
The advantage of protothreads over a purely event-driven approach is
that protothreads provides a sequential code structure that allows for
blocking functions. In purely event-driven systems, blocking must be
implemented by manually breaking the function into two pieces - one
for the piece of code before the blocking call and one for the code
after the blocking call. This makes it hard to use control structures
such as if() conditionals and while() loops.
The advantage of protothreads over ordinary threads is that a
protothread do not require a separate stack. In memory constrained
systems, the overhead of allocating multiple stacks can consume large
amounts of the available memory. In contrast, each protothread only
requires between two and twelve bytes of state, depending on the
architecture.
\note Because protothreads do not save the stack context across a
blocking call, <b>local variables are not preserved when the
protothread blocks</b>. This means that local variables should be used
with utmost care - <b>if in doubt, do not use local variables inside a
protothread!</b>
Main features:
- No machine specific code - the protothreads library is pure C
- Does not use error-prone functions such as longjmp()
- Very small RAM overhead - only two bytes per protothread
- Can be used with or without an OS
- Provides blocking wait without full multi-threading or
stack-switching
Examples applications:
- Memory constrained systems
- Event-driven protocol stacks
- Deeply embedded systems
- Sensor network nodes
The protothreads API consists of four basic operations:
initialization: PT_INIT(), execution: PT_BEGIN(), conditional
blocking: PT_WAIT_UNTIL() and exit: PT_END(). On top of these, two
convenience functions are built: reversed condition blocking:
PT_WAIT_WHILE() and protothread blocking: PT_WAIT_THREAD().
\sa \ref pt "Protothreads API documentation"
The protothreads library is released under a BSD-style license that
allows for both non-commercial and commercial usage. The only
requirement is that credit is given.
\section authors Authors
The protothreads library was written by Adam Dunkels <adam@sics.se>
with support from Oliver Schmidt <ol.sc@web.de>.
\section pt-desc Protothreads
Protothreads are a extremely lightweight, stackless threads that
provides a blocking context on top of an event-driven system, without
the overhead of per-thread stacks. The purpose of protothreads is to
implement sequential flow of control without using complex state
machines or full multi-threading. Protothreads provides conditional
blocking inside a C function.
In memory constrained systems, such as deeply embedded systems,
traditional multi-threading may have a too large memory overhead. In
traditional multi-threading, each thread requires its own stack, that
typically is over-provisioned. The stacks may use large parts of the
available memory.
The main advantage of protothreads over ordinary threads is that
protothreads are very lightweight: a protothread does not require its
own stack. Rather, all protothreads run on the same stack and context
switching is done by stack rewinding. This is advantageous in memory
constrained systems, where a stack for a thread might use a large part
of the available memory. A protothread only requires only two bytes of
memory per protothread. Moreover, protothreads are implemented in pure
C and do not require any machine-specific assembler code.
A protothread runs within a single C function and cannot span over
other functions. A protothread may call normal C functions, but cannot
block inside a called function. Blocking inside nested function calls
is instead made by spawning a separate protothread for each
potentially blocking function. The advantage of this approach is that
blocking is explicit: the programmer knows exactly which functions
that block that which functions the never blocks.
Protothreads are similar to asymmetric co-routines. The main
difference is that co-routines uses a separate stack for each
co-routine, whereas protothreads are stackless. The most similar
mechanism to protothreads are Python generators. These are also
stackless constructs, but have a different purpose. Protothreads
provides blocking contexts inside a C function, whereas Python
generators provide multiple exit points from a generator function.
\section pt-autovars Local variables
\note
Because protothreads do not save the stack context across a blocking
call, local variables are not preserved when the protothread
blocks. This means that local variables should be used with utmost
care - if in doubt, do not use local variables inside a protothread!
\section pt-scheduling Scheduling
A protothread is driven by repeated calls to the function in which the
protothread is running. Each time the function is called, the
protothread will run until it blocks or exits. Thus the scheduling of
protothreads is done by the application that uses protothreads.
\section pt-impl Implementation
Protothreads are implemented using \ref lc "local continuations". A
local continuation represents the current state of execution at a
particular place in the program, but does not provide any call history
or local variables. A local continuation can be set in a specific
function to capture the state of the function. After a local
continuation has been set can be resumed in order to restore the state
of the function at the point where the local continuation was set.
Local continuations can be implemented in a variety of ways:
-# by using machine specific assembler code,
-# by using standard C constructs, or
-# by using compiler extensions.
The first way works by saving and restoring the processor state,
except for stack pointers, and requires between 16 and 32 bytes of
memory per protothread. The exact amount of memory required depends on
the architecture.
The standard C implementation requires only two bytes of state per
protothread and utilizes the C switch() statement in a non-obvious way
that is similar to Duff's device. This implementation does, however,
impose a slight restriction to the code that uses protothreads in that
the code cannot use switch() statements itself.
Certain compilers has C extensions that can be used to implement
protothreads. GCC supports label pointers that can be used for this
purpose. With this implementation, protothreads require 4 bytes of RAM
per protothread.
@{
*/
/** @} */
/** @} */