mCRL2
|
helper macros for coroutines More...
Go to the source code of this file.
Macros | |
#define | _coroutine_ENUMDEF(lblseq) BOOST_PP_SEQ_FOR_EACH(_coroutine_ENUMDEF_1, , lblseq) |
#define | _coroutine_ENUMDEF_1(r, data, label) BOOST_PP_CAT(BOOST_PP_CAT(_coroutine_, label), _enum), |
#define | COROUTINES_SECTION do {{ if (1) {{{ do { |
begin a section with two coroutines | |
#define | COROUTINE_LABELS(locations) |
Declare the interrupt locations for the coroutines. | |
#define | COROUTINE |
Define the code for a coroutine. | |
#define | END_COROUTINE |
Ends the definition of code for a coroutine. | |
#define | END_COROUTINES_SECTION |
Close a section containing coroutines. | |
#define | COROUTINE_WHILE(location, condition) |
a while loop where every iteration incurs one unit of work | |
#define | END_COROUTINE_WHILE |
ends a loop started with COROUTINE_WHILE | |
#define | COROUTINE_FOR(location, init, condition, update) |
a for loop where every iteration incurs one unit of work | |
#define | END_COROUTINE_FOR |
ends a loop started with COROUTINE_FOR | |
#define | COROUTINE_DO_WHILE(location, condition) |
a do { } while loop where every iteration incurs one unit of work | |
#define | END_COROUTINE_DO_WHILE |
ends a loop started with COROUTINE_DO_WHILE | |
#define | TERMINATE_COROUTINE_SUCCESSFULLY() |
terminate the pair of coroutines successfully | |
#define | ABORT_THIS_COROUTINE() |
indicates that this coroutine gives up control to the other one | |
#define | ABORT_OTHER_COROUTINE() |
indicates that the other coroutine should give up control | |
helper macros for coroutines
The following macros are intended to be used for two (stackless) coroutines that are executed in lockstep, i. e. both routines do (approximately) the same amount of work until one of them terminates successfully. The two coroutines are inserted into a code block after each other. Under the hood of the macros, code is produced to switch regularly between the two coroutines.
The macros are to be used within a code block (a function) as follows:
int function(...) { ... COROUTINES_SECTION variable declarations of local variables of both coroutines; COROUTINE_LABELS(labels of both coroutines) COROUTINE code of the first coroutine, with special macros for loops. END_COROUTINE COROUTINE code of the second coroutine, also with special macros for loops. END_COROUTINE END_COROUTINES_SECTION ... return ...; }
Note that the scope of the local variables will be both coroutines; the user has to ensure that one coroutine does not access variables of the other coroutine. If there are some shared parameters where access from both coroutines is required, they may also be declared in the variable declaration section.
The labels of the coroutines are given as a so-called boost sequence: (location1) (location2) (location3)
etc. These labels are interrupt locations, i. e. places where a unit of work is counted and the coroutine may be interrupted (to allow the other coroutine to work). As code without loops always incurs the same time complexity, only loop statements need to be counted. There are three commands to create a loop whose iterations are counted, closely corresponding to `‘normal’' loops:
COROUTINE_WHILE(interrupt location, condition) while (condition) { { loop body; loop body; } } END_COROUTINE_WHILE; COROUTINE_FOR(interrupt location, for (initialisation; initialisation, condition, update) condition; update) { { loop body; loop body; } } END_COROUTINE_FOR; COROUTINE_DO_WHILE(interrupt locatn,condition) do { { loop body; loop body; } } END_COROUTINE_DO_WHILE; while (condition);
These macros hide some code that counts how many iterations have been executed in a loop at the end of each iteration; if one coroutine has done enough work, it is interrupted to let the other catch up. It is assumed that a coroutine does at most SIZE_MAX
units of work. Otherwise, the error "corrupted coroutine state" may occur.
A coroutine may also terminate explicitly by executing the statement TERMINATE_COROUTINE_SUCCESSFULLY();
. If it should no longer execute but has not terminated successfully, it may call ABORT_THIS_COROUTINE();
. If it does no longer allow the other coroutine to run up, it may indicate so by calling ABORT_OTHER_COROUTINE();
.
`‘Approximately the same amount of work’' is defined as: As long as both coroutines run, the difference between the number of steps taken by the two (i. e. the balance of work) always is between -1 and +1.
Definition in file coroutine.h.
#define _coroutine_ENUMDEF | ( | lblseq | ) | BOOST_PP_SEQ_FOR_EACH(_coroutine_ENUMDEF_1, , lblseq) |
_coroutine_ENUMDEF is an internal macro to define an appropriate enumeration type for interrupt locations in a coroutine.
Definition at line 118 of file coroutine.h.
#define _coroutine_ENUMDEF_1 | ( | r, | |
data, | |||
label | |||
) | BOOST_PP_CAT(BOOST_PP_CAT(_coroutine_, label), _enum), |
Definition at line 120 of file coroutine.h.
#define ABORT_OTHER_COROUTINE | ( | ) |
indicates that the other coroutine should give up control
In a situation where one coroutine finds that the other should no longer run, it calls ABORT_OTHER_COROUTINE
.
Definition at line 378 of file coroutine.h.
#define ABORT_THIS_COROUTINE | ( | ) |
indicates that this coroutine gives up control to the other one
In a situation where one coroutine finds that the other should run to completion, it calls ABORT_THIS_COROUTINE
.
Definition at line 363 of file coroutine.h.
#define COROUTINE |
Define the code for a coroutine.
Between COROUTINE and END_COROUTINE, the code for the coroutine is placed. It is required to have exactly two coroutines.
A coroutine is closed with END_COROUTINE
.
(If this is the first coroutine, the case label is ignored because an additional switch statement is included in COROUTINE_LABELS.)
Definition at line 192 of file coroutine.h.
#define COROUTINE_DO_WHILE | ( | location, | |
condition | |||
) |
a do { } while
loop where every iteration incurs one unit of work
A COROUTINE_DO_WHILE
may be interrupted at the end of an iteration to allow the other coroutine to catch up. Note that one has to specify the condition at the beginnin of the loop, even though it will not be tested before the first iteration.
location | a unique interrupt location (one of the locations given as parameter to DEFINE_COROUTINE ) |
condition | the while condition |
Definition at line 314 of file coroutine.h.
#define COROUTINE_FOR | ( | location, | |
init, | |||
condition, | |||
update | |||
) |
a for
loop where every iteration incurs one unit of work
A COROUTINE_FOR
may be interrupted at the end of an iteration to allow the other coroutine to catch up.
location | a unique interrupt location (one of the locations given as parameter to DEFINE_COROUTINE ) |
init | the for initialiser expression |
condition | the for condition |
update | the for update expression (executed near the end of each iteration) |
Definition at line 271 of file coroutine.h.
#define COROUTINE_LABELS | ( | locations | ) |
Declare the interrupt locations for the coroutines.
The call to COROUTINE_LABELS is needed to declare the interrupt locations used in a coroutine. For every loop, there is exactly one interrupt location, which will also be given when the loop is defined in the coroutine.
If additional labels are given to COROUTINE_LABELS, the compiler may complain that a switch() {}
statement with an enum
type does not mention all possible values. The user of the macro should then delete the unused locations from the parameter list of the macro.
Immediately after COROUTINE_LABELS()
, the user should place the first coroutine, indicated by COROUTINE
.
locations | locations where the coroutine can be interrupted, as a boost sequence: (location1) (location2) (location3) etc. |
Definition at line 161 of file coroutine.h.
#define COROUTINE_WHILE | ( | location, | |
condition | |||
) |
a while
loop where every iteration incurs one unit of work
A COROUTINE_WHILE
may be interrupted at the end of an iteration to allow the other coroutine to catch up.
location | a unique interrupt location (one of the locations given as parameter to DEFINE_COROUTINE ) |
condition | the while condition |
Definition at line 227 of file coroutine.h.
#define COROUTINES_SECTION do {{ if (1) {{{ do { |
begin a section with two coroutines
The macro indicates that in the following, a number of coroutines will be defined, which should run in lockstep.
A coroutine section is closed with END_COROUTINES_SECTION
.
Definition at line 142 of file coroutine.h.
#define END_COROUTINE |
Ends the definition of code for a coroutine.
Definition at line 200 of file coroutine.h.
#define END_COROUTINE_DO_WHILE |
ends a loop started with COROUTINE_DO_WHILE
Definition at line 336 of file coroutine.h.
#define END_COROUTINE_FOR |
ends a loop started with COROUTINE_FOR
Definition at line 297 of file coroutine.h.
#define END_COROUTINE_WHILE |
ends a loop started with COROUTINE_WHILE
Definition at line 252 of file coroutine.h.
#define END_COROUTINES_SECTION |
Close a section containing coroutines.
Definition at line 208 of file coroutine.h.
#define TERMINATE_COROUTINE_SUCCESSFULLY | ( | ) |
terminate the pair of coroutines successfully
If called in a coroutine, both coroutines will immediately terminate. The final statement (in RUN_COROUTINES
) of the one that called TERMINATE_COROUTINE_SUCCESSFULLY
will be executed.
Definition at line 348 of file coroutine.h.