File syn_pt.h¶
Go to the source code of this file
Protothreads — stackless cooperative coroutines for C. More...
#include "../common/syn_compiler.h"#include "../common/syn_defs.h"
Classes¶
| Type | Name |
|---|---|
| struct | SYN_PT Protothread control block. |
Public Types¶
| Type | Name |
|---|---|
| enum | SYN_PT_Status Return value from a protothread function. |
Macros¶
| Type | Name |
|---|---|
| define | PT_BEGIN (pt) /* multi line expression */Open a protothread body. Must be the first statement in the protothread function, before any PT_* operations. |
| define | PT_BLOCK_CONDITION (pt, task, cond) /* multi line expression */Sleep task (SYN_TASK_BLOCKED) until explicitly resumed. |
| define | PT_BLOCK_EVENT (pt, task, grp, mask) /* multi line expression */Block until ANY bit in mask is set in the event group. |
| define | PT_BLOCK_EVENT_WITH_TIMEOUT (pt, task, grp, mask, timeout_ms, out_flags) /* multi line expression */Block task execution (SYN_TASK_BLOCKED) until ANY bit in mask is set ORtimeout_ms milliseconds elapse. |
| define | PT_DEFER (pt, task) /* multi line expression */Defer to all ready tasks, regardless of priority. |
| define | PT_DELAY_MS (pt, target, ms) /* multi line expression */Non-blocking delay for ms milliseconds. |
| define | PT_DELAY_US (pt, target, us) /* multi line expression */Non-blocking sub-millisecond delay for us microseconds. |
| define | PT_END (pt) /* multi line expression */Close a protothread body. Returns PT_EXITED and resets the continuation so the thread can be restarted if desired. |
| define | PT_EXIT (pt) /* multi line expression */Terminate the protothread immediately. |
| define | PT_INIT (pt) ((pt)->lc = 0)Initialize (or reset) a protothread so it starts from the top. |
| define | PT_IS_IDLE (pt) ((pt)->lc == 0) |
| define | PT_IS_RUNNING (pt) ((pt)->lc != 0) |
| define | PT_RESTART (pt) /* multi line expression */Reset the protothread and restart from PT_BEGIN on next call. |
| define | PT_SPAWN (pt, child, func) /* multi line expression */Spawn a child protothread and block until it exits. |
| define | PT_TASK_DELAY_MS (pt, task, ms) [**PT\_DELAY\_MS**](syn__pt_8h.md#define-pt_delay_ms)(pt, &(task)->delay\_until, ms)Convenience form for use with the scheduler's SYN_Task (milliseconds). |
| define | PT_WAIT_UNTIL (pt, cond) /* multi line expression */Block until cond evaluates to true. |
| define | PT_WAIT_WHILE (pt, cond) [**PT\_WAIT\_UNTIL**](syn__pt_8h.md#define-pt_wait_until)(pt, !(cond))Block while cond is true. Dual of PT_WAIT_UNTIL. |
| define | PT_YIELD (pt) /* multi line expression */Yield control unconditionally. The protothread will resume at this point on the next call. |
| define | PT_YIELD_UNTIL (pt, cond) /* multi line expression */Yield while cond is true. |
Detailed Description¶
Protothreads provide lightweight, cooperative multitasking without requiring a separate stack per thread. Each protothread is a normal C function that uses macros to save and restore its execution position via the switch/__LINE__ continuation trick (Duff's device).
A protothread costs 2 bytes of RAM (the continuation variable).
** **
- You cannot use a bare
switchstatement inside a protothread body (useif/else ifchains instead). - Local variables are NOT preserved across yield/wait points. Store persistent state in
staticvariables, globals, or a struct passed via the task'suser_datapointer. - A protothread must reside entirely within a single function.
** **
static SYN_PT pt;
PT_INIT(&pt);
while (1) {
my_protothread(&pt);
// ... poll other protothreads ...
}
** **
// See syn_sched.h for the full pattern.
static SYN_PT_Status my_task(SYN_PT *pt, SYN_Task *task) {
PT_BEGIN(pt);
// ...
PT_END(pt);
}
** **
// High-level C code
SYN_PT_Status my_task(SYN_PT *pt) {
PT_BEGIN(pt);
PT_WAIT_UNTIL(pt, flag == 1);
PT_END(pt);
}
// Expands preprocessor output to:
SYN_PT_Status my_task(SYN_PT *pt) {
char _pt_yield_flag = 1;
switch (pt->lc) {
case 0:
// On resume, switch(pt->lc) jumps directly to case 12:
pt->lc = 12; case 12:
if (!(flag == 1)) return PT_WAITING;
}
_pt_yield_flag = 0;
PT_INIT(pt);
return PT_EXITED;
}
Public Types Documentation¶
enum SYN_PT_Status¶
Return value from a protothread function.
Macro Definition Documentation¶
define PT_BEGIN¶
Open a protothread body. Must be the first statement in the protothread function, before any PT_* operations.
Expands to the head of a switch statement that jumps to the last saved continuation point.
define PT_BLOCK_CONDITION¶
Sleep task (SYN_TASK_BLOCKED) until explicitly resumed.
Warning:
This macro does NOT poll cond on each scheduler tick. Once the task yields as BLOCKED, the scheduler skips it entirely. The condition is only re-evaluated when the task is explicitly woken by an ISR or driver calling syn_task_resume(task).
For polled condition blocking, use PT_WAIT_UNTIL(pt, cond) instead. For event-flag-driven blocking, use PT_BLOCK_EVENT(pt, task, grp, mask).
Parameters:
ptProtothread.taskPointer to the SYN_Task struct.condBoolean condition expression to evaluate.
define PT_BLOCK_EVENT¶
Block until ANY bit in mask is set in the event group.
Unlike PT_WAIT_EVENT (which polls every scheduler pass), this macro sets the task state to BLOCKED. The scheduler skips the task entirely until the event fires, saving CPU and enabling proper tickless sleep.
Matched flags are auto-cleared after the task resumes.
Note:
The clear runs after PT_YIELD returns (i.e. after the scheduler has already detected the flags during its scan), so it is safe for the scheduler to use the flags as a wakeup condition.
Parameters:
ptProtothread.taskPointer to the SYN_Task struct.grpPointer to SYN_EventGroup.maskBitmask of event flags to wait for (any of them).
define PT_BLOCK_EVENT_WITH_TIMEOUT¶
Block task execution (SYN_TASK_BLOCKED) until ANY bit in mask is set ORtimeout_ms milliseconds elapse.
#define PT_BLOCK_EVENT_WITH_TIMEOUT (
pt,
task,
grp,
mask,
timeout_ms,
out_flags
) `/* multi line expression */`
Combines event-flag blocking with millisecond deadline tracking. The task is skipped by the scheduler until either the event fires or the timeout deadline passes.
Matched event flags are captured into out_flags (if non-NULL) and auto-cleared ONLY if the event actually fired before the timeout. Check *out_flags != 0 to determine if the event fired vs timed out.
Parameters:
ptProtothread.taskPointer to the SYN_Task struct.grpPointer to SYN_EventFlags.maskBitmask of event flags to wait for.timeout_msTimeout duration in milliseconds.out_flagsPointer to uint32_t receiving matched flags (or 0 on timeout).
define PT_DEFER¶
Defer to all ready tasks, regardless of priority.
Unlike PT_YIELD (which only round-robins among equal-priority tasks), this macro allows any lower-priority ready task to run before this task is scheduled again. The task is skipped for exactly one scheduler pass.
Use this when a high-priority task has no immediate work but doesn't want to commit to a timed delay.
Parameters:
ptProtothread.taskPointer to the SYN_Task struct.
define PT_DELAY_MS¶
Non-blocking delay for ms milliseconds.
Requires a uint32_t variable to store the deadline. When used with the scheduler, pass &(task)->delay_until. For standalone use, pass any persistent uint32_t *.
Note:
The target is reset to 0 (the scheduler's "no deadline pending" sentinel) once the delay completes. A deadline left in place would read as "in the future" again after the tick counter advances 2^31 ms (~24.8 days) past it, freezing the task. A computed deadline of exactly 0 (tick wrap) is nudged to 1 so it cannot alias the sentinel.
Parameters:
ptProtothread.targetPointer to a uint32_t that will hold the deadline tick.msDelay duration in milliseconds.
define PT_DELAY_US¶
Non-blocking sub-millisecond delay for us microseconds.
Requires a user-supplied persistent uint32_t variable (e.g., static uint32_t us_target;). Does not modify SYN_Task.delay_until to avoid corrupting the millisecond scheduler timebase.
Parameters:
ptProtothread.targetPointer to a uint32_t variable holding the microsecond deadline.usDelay duration in microseconds.
define PT_END¶
Close a protothread body. Returns PT_EXITED and resets the continuation so the thread can be restarted if desired.
define PT_EXIT¶
Terminate the protothread immediately.
define PT_INIT¶
Initialize (or reset) a protothread so it starts from the top.
define PT_IS_IDLE¶
Check if a protothread has not yet started or has been reset.
define PT_IS_RUNNING¶
Check if a protothread is still running (has not exited).
define PT_RESTART¶
Reset the protothread and restart from PT_BEGIN on next call.
define PT_SPAWN¶
Spawn a child protothread and block until it exits.
Parameters:
ptParent protothread.childChild protothread (SYN_PT struct).funcExpression that calls the child's function, e.g.child_func(&child_pt).
Warning:
The func expression is evaluated on EVERY scheduler poll until the child exits. Never pass expressions with side-effects (e.g. counter++, function calls that modify state). Pre-evaluate arguments before calling PT_SPAWN.
Usage:
define PT_TASK_DELAY_MS¶
Convenience form for use with the scheduler's SYN_Task (milliseconds).
Parameters:
ptProtothread.taskPointer to the SYN_Task struct.msDelay duration in milliseconds.
define PT_WAIT_UNTIL¶
Block until cond evaluates to true.
Each time the protothread is polled and cond is false, it returns PT_WAITING and resumes at this point on the next call.
define PT_WAIT_WHILE¶
Block while cond is true. Dual of PT_WAIT_UNTIL.
define PT_YIELD¶
Yield control unconditionally. The protothread will resume at this point on the next call.
define PT_YIELD_UNTIL¶
Yield while cond is true.
Like PT_WAIT_WHILE, but returns PT_YIELDED instead of PT_WAITING, signaling the scheduler that this thread actively wants to run.
Warning:
Priority starvation hazard: A high-priority task using PT_YIELD_UNTIL to wait for a resource held by a lower-priority task will spin-yield every tick, starving the lower-priority task from ever releasing the resource. Use PT_WAIT_UNTIL(pt, cond) for inter-task resource contention, and reserve PT_YIELD_UNTIL for sub-tick hardware polling only.
The documentation for this class was generated from the following file src/syntropic/pt/syn_pt.h