xref: /nrf52832-nimble/rt-thread/components/net/uip/doc/pt-doc.txt (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero/**
2*10465441SEvalZero\defgroup pt Protothreads
3*10465441SEvalZero
4*10465441SEvalZeroProtothreads are a type of lightweight stackless threads designed for
5*10465441SEvalZeroseverly memory constrained systems such as deeply embedded systems or
6*10465441SEvalZerosensor network nodes. Protothreads provides linear code execution for
7*10465441SEvalZeroevent-driven systems implemented in C. Protothreads can be used with
8*10465441SEvalZeroor without an RTOS.
9*10465441SEvalZero
10*10465441SEvalZeroProtothreads are a extremely lightweight, stackless type of threads
11*10465441SEvalZerothat provides a blocking context on top of an event-driven system,
12*10465441SEvalZerowithout the overhead of per-thread stacks. The purpose of protothreads
13*10465441SEvalZerois to implement sequential flow of control without complex state
14*10465441SEvalZeromachines or full multi-threading. Protothreads provides conditional
15*10465441SEvalZeroblocking inside C functions.
16*10465441SEvalZero
17*10465441SEvalZeroThe advantage of protothreads over a purely event-driven approach is
18*10465441SEvalZerothat protothreads provides a sequential code structure that allows for
19*10465441SEvalZeroblocking functions. In purely event-driven systems, blocking must be
20*10465441SEvalZeroimplemented by manually breaking the function into two pieces - one
21*10465441SEvalZerofor the piece of code before the blocking call and one for the code
22*10465441SEvalZeroafter the blocking call. This makes it hard to use control structures
23*10465441SEvalZerosuch as if() conditionals and while() loops.
24*10465441SEvalZero
25*10465441SEvalZeroThe advantage of protothreads over ordinary threads is that a
26*10465441SEvalZeroprotothread do not require a separate stack. In memory constrained
27*10465441SEvalZerosystems, the overhead of allocating multiple stacks can consume large
28*10465441SEvalZeroamounts of the available memory. In contrast, each protothread only
29*10465441SEvalZerorequires between two and twelve bytes of state, depending on the
30*10465441SEvalZeroarchitecture.
31*10465441SEvalZero
32*10465441SEvalZero\note Because protothreads do not save the stack context across a
33*10465441SEvalZeroblocking call, <b>local variables are not preserved when the
34*10465441SEvalZeroprotothread blocks</b>. This means that local variables should be used
35*10465441SEvalZerowith utmost care - <b>if in doubt, do not use local variables inside a
36*10465441SEvalZeroprotothread!</b>
37*10465441SEvalZero
38*10465441SEvalZero
39*10465441SEvalZeroMain features:
40*10465441SEvalZero
41*10465441SEvalZero    - No machine specific code - the protothreads library is pure C
42*10465441SEvalZero
43*10465441SEvalZero    - Does not use error-prone functions such as longjmp()
44*10465441SEvalZero
45*10465441SEvalZero    - Very small RAM overhead - only two bytes per protothread
46*10465441SEvalZero
47*10465441SEvalZero    - Can be used with or without an OS
48*10465441SEvalZero
49*10465441SEvalZero    - Provides blocking wait without full multi-threading or
50*10465441SEvalZero      stack-switching
51*10465441SEvalZero
52*10465441SEvalZeroExamples applications:
53*10465441SEvalZero
54*10465441SEvalZero    - Memory constrained systems
55*10465441SEvalZero
56*10465441SEvalZero    - Event-driven protocol stacks
57*10465441SEvalZero
58*10465441SEvalZero    - Deeply embedded systems
59*10465441SEvalZero
60*10465441SEvalZero    - Sensor network nodes
61*10465441SEvalZero
62*10465441SEvalZeroThe protothreads API consists of four basic operations:
63*10465441SEvalZeroinitialization: PT_INIT(), execution: PT_BEGIN(), conditional
64*10465441SEvalZeroblocking: PT_WAIT_UNTIL() and exit: PT_END(). On top of these, two
65*10465441SEvalZeroconvenience functions are built: reversed condition blocking:
66*10465441SEvalZeroPT_WAIT_WHILE() and protothread blocking: PT_WAIT_THREAD().
67*10465441SEvalZero
68*10465441SEvalZero\sa \ref pt "Protothreads API documentation"
69*10465441SEvalZero
70*10465441SEvalZeroThe protothreads library is released under a BSD-style license that
71*10465441SEvalZeroallows for both non-commercial and commercial usage. The only
72*10465441SEvalZerorequirement is that credit is given.
73*10465441SEvalZero
74*10465441SEvalZero\section authors Authors
75*10465441SEvalZero
76*10465441SEvalZeroThe protothreads library was written by Adam Dunkels <[email protected]>
77*10465441SEvalZerowith support from Oliver Schmidt <[email protected]>.
78*10465441SEvalZero
79*10465441SEvalZero\section pt-desc Protothreads
80*10465441SEvalZero
81*10465441SEvalZeroProtothreads are a extremely lightweight, stackless threads that
82*10465441SEvalZeroprovides a blocking context on top of an event-driven system, without
83*10465441SEvalZerothe overhead of per-thread stacks. The purpose of protothreads is to
84*10465441SEvalZeroimplement sequential flow of control without using complex state
85*10465441SEvalZeromachines or full multi-threading. Protothreads provides conditional
86*10465441SEvalZeroblocking inside a C function.
87*10465441SEvalZero
88*10465441SEvalZeroIn memory constrained systems, such as deeply embedded systems,
89*10465441SEvalZerotraditional multi-threading may have a too large memory overhead. In
90*10465441SEvalZerotraditional multi-threading, each thread requires its own stack, that
91*10465441SEvalZerotypically is over-provisioned. The stacks may use large parts of the
92*10465441SEvalZeroavailable memory.
93*10465441SEvalZero
94*10465441SEvalZeroThe main advantage of protothreads over ordinary threads is that
95*10465441SEvalZeroprotothreads are very lightweight: a protothread does not require its
96*10465441SEvalZeroown stack. Rather, all protothreads run on the same stack and context
97*10465441SEvalZeroswitching is done by stack rewinding. This is advantageous in memory
98*10465441SEvalZeroconstrained systems, where a stack for a thread might use a large part
99*10465441SEvalZeroof the available memory. A protothread only requires only two bytes of
100*10465441SEvalZeromemory per protothread. Moreover, protothreads are implemented in pure
101*10465441SEvalZeroC and do not require any machine-specific assembler code.
102*10465441SEvalZero
103*10465441SEvalZeroA protothread runs within a single C function and cannot span over
104*10465441SEvalZeroother functions. A protothread may call normal C functions, but cannot
105*10465441SEvalZeroblock inside a called function. Blocking inside nested function calls
106*10465441SEvalZerois instead made by spawning a separate protothread for each
107*10465441SEvalZeropotentially blocking function. The advantage of this approach is that
108*10465441SEvalZeroblocking is explicit: the programmer knows exactly which functions
109*10465441SEvalZerothat block that which functions the never blocks.
110*10465441SEvalZero
111*10465441SEvalZeroProtothreads are similar to asymmetric co-routines. The main
112*10465441SEvalZerodifference is that co-routines uses a separate stack for each
113*10465441SEvalZeroco-routine, whereas protothreads are stackless. The most similar
114*10465441SEvalZeromechanism to protothreads are Python generators. These are also
115*10465441SEvalZerostackless constructs, but have a different purpose. Protothreads
116*10465441SEvalZeroprovides blocking contexts inside a C function, whereas Python
117*10465441SEvalZerogenerators provide multiple exit points from a generator function.
118*10465441SEvalZero
119*10465441SEvalZero\section pt-autovars Local variables
120*10465441SEvalZero
121*10465441SEvalZero\note
122*10465441SEvalZeroBecause protothreads do not save the stack context across a blocking
123*10465441SEvalZerocall, local variables are not preserved when the protothread
124*10465441SEvalZeroblocks. This means that local variables should be used with utmost
125*10465441SEvalZerocare - if in doubt, do not use local variables inside a protothread!
126*10465441SEvalZero
127*10465441SEvalZero\section pt-scheduling Scheduling
128*10465441SEvalZero
129*10465441SEvalZeroA protothread is driven by repeated calls to the function in which the
130*10465441SEvalZeroprotothread is running. Each time the function is called, the
131*10465441SEvalZeroprotothread will run until it blocks or exits. Thus the scheduling of
132*10465441SEvalZeroprotothreads is done by the application that uses protothreads.
133*10465441SEvalZero
134*10465441SEvalZero\section pt-impl Implementation
135*10465441SEvalZero
136*10465441SEvalZeroProtothreads are implemented using \ref lc "local continuations". A
137*10465441SEvalZerolocal continuation represents the current state of execution at a
138*10465441SEvalZeroparticular place in the program, but does not provide any call history
139*10465441SEvalZeroor local variables. A local continuation can be set in a specific
140*10465441SEvalZerofunction to capture the state of the function. After a local
141*10465441SEvalZerocontinuation has been set can be resumed in order to restore the state
142*10465441SEvalZeroof the function at the point where the local continuation was set.
143*10465441SEvalZero
144*10465441SEvalZero
145*10465441SEvalZeroLocal continuations can be implemented in a variety of ways:
146*10465441SEvalZero
147*10465441SEvalZero   -# by using machine specific assembler code,
148*10465441SEvalZero   -# by using standard C constructs, or
149*10465441SEvalZero   -# by using compiler extensions.
150*10465441SEvalZero
151*10465441SEvalZeroThe first way works by saving and restoring the processor state,
152*10465441SEvalZeroexcept for stack pointers, and requires between 16 and 32 bytes of
153*10465441SEvalZeromemory per protothread. The exact amount of memory required depends on
154*10465441SEvalZerothe architecture.
155*10465441SEvalZero
156*10465441SEvalZeroThe standard C implementation requires only two bytes of state per
157*10465441SEvalZeroprotothread and utilizes the C switch() statement in a non-obvious way
158*10465441SEvalZerothat is similar to Duff's device. This implementation does, however,
159*10465441SEvalZeroimpose a slight restriction to the code that uses protothreads in that
160*10465441SEvalZerothe code cannot use switch() statements itself.
161*10465441SEvalZero
162*10465441SEvalZeroCertain compilers has C extensions that can be used to implement
163*10465441SEvalZeroprotothreads. GCC supports label pointers that can be used for this
164*10465441SEvalZeropurpose. With this implementation, protothreads require 4 bytes of RAM
165*10465441SEvalZeroper protothread.
166*10465441SEvalZero
167*10465441SEvalZero@{
168*10465441SEvalZero
169*10465441SEvalZero
170*10465441SEvalZero*/
171*10465441SEvalZero
172*10465441SEvalZero/** @} */
173*10465441SEvalZero
174