ssm
Runtime Library for the Sparse Synchronous Model
|
Data Structures | |
struct | ssm_act |
Activation record for an SSM routine. More... | |
struct | ssm_trigger |
Indicates a routine should run when a scheduled variable is written. More... | |
struct | ssm_sv |
A variable that may have scheduled updates and triggers. More... | |
struct | ssm_bool_t |
Scheduled Boolean variable. More... | |
struct | ssm_i8_t |
Scheduled 8-bit Signed Integer variable. More... | |
struct | ssm_i16_t |
Scheduled 16-bit Signed Integer variable. More... | |
struct | ssm_i32_t |
Scheduled 32-bit Signed Integer variable. More... | |
struct | ssm_i64_t |
Scheduled 64-bit Signed Integer variable. More... | |
struct | ssm_u8_t |
Scheduled 8-bit Unsigned Integer variable. More... | |
struct | ssm_u16_t |
Scheduled 16-bit Unsigned Integer variable. More... | |
struct | ssm_u32_t |
Scheduled 32-bit Unsigned Integer variable. More... | |
struct | ssm_u64_t |
Scheduled 64-bit Unsigned Integer variable. More... | |
Macros | |
#define | SSM_ACT_MALLOC(size) malloc(size) |
Allocation function for activation records. More... | |
#define | SSM_ACT_FREE(ptr, size) free(ptr) |
Free function for activation records. More... | |
#define | SSM_RESOURCES_EXHAUSTED(string) exit(1) |
Invoked when limited resources are exhausted, e.g., unable to allocate memory, no more queue space. More... | |
#define | SSM_SECOND 1000000000L |
Ticks in a second. More... | |
#define | SSM_NANOSECOND (SSM_SECOND/1000000000L) |
Ticks per nanosecond. More... | |
#define | SSM_MICROSECOND (SSM_SECOND/1000000L) |
Ticks per microsecond. More... | |
#define | SSM_MILLISECOND (SSM_SECOND/1000L) |
Ticks per millisecond. More... | |
#define | SSM_MINUTE (SSM_SECOND*60L) |
Ticks per minute. More... | |
#define | SSM_HOUR (SSM_SECOND*3600L) |
Ticks per hour. More... | |
#define | SSM_NEVER UINT64_MAX |
Time indicating something will never happen. More... | |
#define | SSM_ROOT_PRIORITY 0 |
The priority for the entry point of an SSM program. More... | |
#define | SSM_ROOT_DEPTH (sizeof(ssm_priority_t) * 8) |
The depth at the entry point of an SSM program. More... | |
#define | SSM_ACT_FIELDS |
"Base class" fields for user-defined activation records More... | |
#define | member_type(type, member) const void |
Implementation of container_of that falls back to ISO C99 when GNU C is not available (from https://stackoverflow.com/a/10269925/10497710) More... | |
#define | container_of(ptr, type, member) |
#define | ssm_later_event(var, then) ssm_schedule((var), (then)) |
#define | SSM_DECLARE_SV_SCALAR(payload_t) |
#define | SSM_DEFINE_SV_SCALAR(payload_t) |
Typedefs | |
typedef uint64_t | ssm_time_t |
Absolute time; never to overflow. More... | |
typedef uint32_t | ssm_priority_t |
Thread priority. More... | |
typedef uint8_t | ssm_depth_t |
Index of least significant bit in a group of priorities. More... | |
typedef void | ssm_stepf_t(struct ssm_act *) |
The function that does an instant's work for a routine. More... | |
typedef struct ssm_act | ssm_act_t |
Activation record for an SSM routine. More... | |
typedef struct ssm_trigger | ssm_trigger_t |
Indicates a routine should run when a scheduled variable is written. More... | |
typedef struct ssm_sv | ssm_sv_t |
A variable that may have scheduled updates and triggers. More... | |
typedef ssm_sv_t | ssm_event_t |
typedef int8_t | i8 |
8-bit Signed Integer More... | |
typedef int16_t | i16 |
16-bit Signed Integer More... | |
typedef int32_t | i32 |
32-bit Signed Integer More... | |
typedef int64_t | i64 |
64-bit Signed Integer More... | |
typedef uint8_t | u8 |
8-bit Unsigned Integer More... | |
typedef uint16_t | u16 |
16-bit Unsigned Integer More... | |
typedef uint32_t | u32 |
32-bit Unsigned Integer More... | |
typedef uint64_t | u64 |
64-bit Unsigned Integer More... | |
Functions | |
void | ssm_sensitize (ssm_sv_t *, ssm_trigger_t *) |
Indicate writing to a variable should trigger a routine. More... | |
void | ssm_desensitize (ssm_trigger_t *) |
Disable a sensitized routine. More... | |
void | ssm_activate (ssm_act_t *) |
Schedule a routine to run in the current instant. More... | |
static void | ssm_call (ssm_act_t *act) |
Execute a routine immediately. More... | |
static ssm_act_t * | ssm_enter (size_t bytes, ssm_stepf_t *step, ssm_act_t *parent, ssm_priority_t priority, ssm_depth_t depth) |
Enter a routine. More... | |
static void | ssm_leave (ssm_act_t *act, size_t bytes) |
Deallocate an activation record; return to caller if we were the last child. More... | |
bool | ssm_event_on (ssm_sv_t *var) |
Return true if there is an event on the given variable in the current instant. More... | |
void | ssm_initialize (ssm_sv_t *var, void(*update)(ssm_sv_t *)) |
Initialize a scheduled variable. More... | |
void | ssm_schedule (ssm_sv_t *var, ssm_time_t later) |
Schedule a future update to a variable. More... | |
void | ssm_unschedule (ssm_sv_t *var) |
Unschedule any pending event on a variable. More... | |
void | ssm_trigger (ssm_sv_t *var, ssm_priority_t priority) |
Activate routines triggered by a variable. More... | |
ssm_time_t | ssm_next_event_time (void) |
Return the time of the next event in the queue or SSM_NEVER. More... | |
ssm_time_t | ssm_now (void) |
Return the current model time. More... | |
void | ssm_tick () |
Run the system for the next scheduled instant. More... | |
void | ssm_reset () |
Reset the scheduler. More... | |
void | ssm_assign_event (ssm_event_t *var, ssm_priority_t prio) |
void | ssm_initialize_event (ssm_event_t *) |
void | ssm_assign_bool (ssm_bool_t *sv, ssm_priority_t prio, const bool value) |
void | ssm_later_bool (ssm_bool_t *sv, ssm_time_t then, const bool value) |
void | ssm_initialize_bool (ssm_bool_t *v) |
void | ssm_assign_i8 (ssm_i8_t *sv, ssm_priority_t prio, const i8 value) |
void | ssm_later_i8 (ssm_i8_t *sv, ssm_time_t then, const i8 value) |
void | ssm_initialize_i8 (ssm_i8_t *v) |
void | ssm_assign_i16 (ssm_i16_t *sv, ssm_priority_t prio, const i16 value) |
void | ssm_later_i16 (ssm_i16_t *sv, ssm_time_t then, const i16 value) |
void | ssm_initialize_i16 (ssm_i16_t *v) |
void | ssm_assign_i32 (ssm_i32_t *sv, ssm_priority_t prio, const i32 value) |
void | ssm_later_i32 (ssm_i32_t *sv, ssm_time_t then, const i32 value) |
void | ssm_initialize_i32 (ssm_i32_t *v) |
void | ssm_assign_i64 (ssm_i64_t *sv, ssm_priority_t prio, const i64 value) |
void | ssm_later_i64 (ssm_i64_t *sv, ssm_time_t then, const i64 value) |
void | ssm_initialize_i64 (ssm_i64_t *v) |
void | ssm_assign_u8 (ssm_u8_t *sv, ssm_priority_t prio, const u8 value) |
void | ssm_later_u8 (ssm_u8_t *sv, ssm_time_t then, const u8 value) |
void | ssm_initialize_u8 (ssm_u8_t *v) |
void | ssm_assign_u16 (ssm_u16_t *sv, ssm_priority_t prio, const u16 value) |
void | ssm_later_u16 (ssm_u16_t *sv, ssm_time_t then, const u16 value) |
void | ssm_initialize_u16 (ssm_u16_t *v) |
void | ssm_assign_u32 (ssm_u32_t *sv, ssm_priority_t prio, const u32 value) |
void | ssm_later_u32 (ssm_u32_t *sv, ssm_time_t then, const u32 value) |
void | ssm_initialize_u32 (ssm_u32_t *v) |
void | ssm_assign_u64 (ssm_u64_t *sv, ssm_priority_t prio, const u64 value) |
void | ssm_later_u64 (ssm_u64_t *sv, ssm_time_t then, const u64 value) |
void | ssm_initialize_u64 (ssm_u64_t *v) |
Variables | |
ssm_act_t | ssm_top_parent |
An activation record for the parent of the topmost routine. More... | |
#define container_of | ( | ptr, | |
type, | |||
member | |||
) |
#define member_type | ( | type, | |
member | |||
) | const void |
Implementation of container_of that falls back to ISO C99 when GNU C is not available (from https://stackoverflow.com/a/10269925/10497710)
#define SSM_ACT_FIELDS |
"Base class" fields for user-defined activation records
The same fields as struct ssm_act.
Define your own activation record types like this:
typedef struct { SSM_ACT_FIELDS; struct ssm_trigger trigger1; ssm_int8_t mysv; } myact_t;
#define SSM_ACT_FREE | ( | ptr, | |
size | |||
) | free(ptr) |
Free function for activation records.
The first argument is a pointer to the base of the activation record being freed; the second is the size in bytes of the record being freed.
#define SSM_ACT_MALLOC | ( | size | ) | malloc(size) |
Allocation function for activation records.
Given a number of bytes, return a void pointer to the base of newly allocated space or 0 if no additional space is available
#define SSM_DECLARE_SV_SCALAR | ( | payload_t | ) |
#define SSM_DEFINE_SV_SCALAR | ( | payload_t | ) |
#define SSM_HOUR (SSM_SECOND*3600L) |
Ticks per hour.
#define ssm_later_event | ( | var, | |
then | |||
) | ssm_schedule((var), (then)) |
#define SSM_MICROSECOND (SSM_SECOND/1000000L) |
Ticks per microsecond.
#define SSM_MILLISECOND (SSM_SECOND/1000L) |
Ticks per millisecond.
#define SSM_MINUTE (SSM_SECOND*60L) |
Ticks per minute.
#define SSM_NANOSECOND (SSM_SECOND/1000000000L) |
Ticks per nanosecond.
#define SSM_NEVER UINT64_MAX |
Time indicating something will never happen.
The value of this must be derived from the type of ssm_time_t
#define SSM_RESOURCES_EXHAUSTED | ( | string | ) | exit(1) |
Invoked when limited resources are exhausted, e.g., unable to allocate memory, no more queue space.
Not expected to return
Argument passed is a string indicating where the failure occurred.
#define SSM_ROOT_DEPTH (sizeof(ssm_priority_t) * 8) |
The depth at the entry point of an SSM program.
#define SSM_ROOT_PRIORITY 0 |
The priority for the entry point of an SSM program.
#define SSM_SECOND 1000000000L |
Ticks in a second.
Override this according to your platform
typedef int16_t i16 |
16-bit Signed Integer
typedef int32_t i32 |
32-bit Signed Integer
typedef int64_t i64 |
64-bit Signed Integer
typedef int8_t i8 |
8-bit Signed Integer
Activation record for an SSM routine.
Routine activation record "base class." A struct for a particular routine must start with this type but then may be followed by routine-specific fields. See SSM_ACT_FIELDS
typedef uint8_t ssm_depth_t |
Index of least significant bit in a group of priorities.
This only needs to represent the number of bits in the ssm_priority_t type.
typedef ssm_sv_t ssm_event_t |
typedef uint32_t ssm_priority_t |
Thread priority.
Lower numbers execute first in an instant
typedef void ssm_stepf_t(struct ssm_act *) |
The function that does an instant's work for a routine.
A variable that may have scheduled updates and triggers.
This is the "base class" for other scheduled variable types.
On its own, this represents a pure event variable, i.e., a scheduled variable with no data/payload. The presence of an event on such a variable can be tested with ssm_event_on() as well as awaited with triggers.
The update field must point to code that copies the new value of the scheduled variable into its current value. For pure events, this function may do nothing, but the pointer must be non-zero.
This can also be embedded in a wrapper struct/class to implement a scheduled variable with a payload. In this case, the payload should also be embedded in that wrapper class, and the vtable should have update/assign/later methods specialized to be aware of the size and layout of the wrapper class.
An invariant: later_time
!= SSM_NEVER if and only if this variable in the event queue.
typedef uint64_t ssm_time_t |
Absolute time; never to overflow.
typedef struct ssm_trigger ssm_trigger_t |
Indicates a routine should run when a scheduled variable is written.
Node in linked list of activation records, maintained by each scheduled variable to determine which continuations should be scheduled when the variable is updated.
typedef uint16_t u16 |
16-bit Unsigned Integer
typedef uint32_t u32 |
32-bit Unsigned Integer
typedef uint64_t u64 |
64-bit Unsigned Integer
typedef uint8_t u8 |
8-bit Unsigned Integer
void ssm_activate | ( | ssm_act_t * | ) |
Schedule a routine to run in the current instant.
Enter the given activation record into the queue of activation records. This is idempotent: it may be called multiple times on the same activation record within an instant; only the first call has any effect.
Invokes SSM_RESOURCES_EXHAUSTED("ssm_activate") if the activation record queue is full.
void ssm_assign_bool | ( | ssm_bool_t * | sv, |
ssm_priority_t | prio, | ||
const bool | value | ||
) |
void ssm_assign_event | ( | ssm_event_t * | var, |
ssm_priority_t | prio | ||
) |
void ssm_assign_i16 | ( | ssm_i16_t * | sv, |
ssm_priority_t | prio, | ||
const i16 | value | ||
) |
void ssm_assign_i32 | ( | ssm_i32_t * | sv, |
ssm_priority_t | prio, | ||
const i32 | value | ||
) |
void ssm_assign_i64 | ( | ssm_i64_t * | sv, |
ssm_priority_t | prio, | ||
const i64 | value | ||
) |
void ssm_assign_i8 | ( | ssm_i8_t * | sv, |
ssm_priority_t | prio, | ||
const i8 | value | ||
) |
void ssm_assign_u16 | ( | ssm_u16_t * | sv, |
ssm_priority_t | prio, | ||
const u16 | value | ||
) |
void ssm_assign_u32 | ( | ssm_u32_t * | sv, |
ssm_priority_t | prio, | ||
const u32 | value | ||
) |
void ssm_assign_u64 | ( | ssm_u64_t * | sv, |
ssm_priority_t | prio, | ||
const u64 | value | ||
) |
void ssm_assign_u8 | ( | ssm_u8_t * | sv, |
ssm_priority_t | prio, | ||
const u8 | value | ||
) |
|
inlinestatic |
Execute a routine immediately.
void ssm_desensitize | ( | ssm_trigger_t * | ) |
Disable a sensitized routine.
Remove the trigger from its variable. Only call this on a previously-sensitized trigger.
|
inlinestatic |
Enter a routine.
Enter a function: allocate the activation record by invoking SSM_ACT_MALLOC, set up the function and program counter value, and remember the caller.
Invokes SSM_RESOURCES_EXHAUSTED("ssm_enter") if allocation fails.
bytes | size of the activation record, >0 |
step | Pointer to "step" function, non-NULL |
parent | Activation record of caller, non-NULL |
priority | Priority: must be no less than parent's |
depth | Depth; used if this routine has children |
bool ssm_event_on | ( | ssm_sv_t * | var | ) |
Return true if there is an event on the given variable in the current instant.
var | Variable: must be non-NULL |
Initialize a scheduled variable.
Call this to initialize the contents of a newly allocated scheduled variable, e.g., after ssm_enter()
void ssm_initialize_bool | ( | ssm_bool_t * | v | ) |
void ssm_initialize_event | ( | ssm_event_t * | ) |
void ssm_initialize_i16 | ( | ssm_i16_t * | v | ) |
void ssm_initialize_i32 | ( | ssm_i32_t * | v | ) |
void ssm_initialize_i64 | ( | ssm_i64_t * | v | ) |
void ssm_initialize_i8 | ( | ssm_i8_t * | v | ) |
void ssm_initialize_u16 | ( | ssm_u16_t * | v | ) |
void ssm_initialize_u32 | ( | ssm_u32_t * | v | ) |
void ssm_initialize_u64 | ( | ssm_u64_t * | v | ) |
void ssm_initialize_u8 | ( | ssm_u8_t * | v | ) |
void ssm_later_bool | ( | ssm_bool_t * | sv, |
ssm_time_t | then, | ||
const bool | value | ||
) |
void ssm_later_i16 | ( | ssm_i16_t * | sv, |
ssm_time_t | then, | ||
const i16 | value | ||
) |
void ssm_later_i32 | ( | ssm_i32_t * | sv, |
ssm_time_t | then, | ||
const i32 | value | ||
) |
void ssm_later_i64 | ( | ssm_i64_t * | sv, |
ssm_time_t | then, | ||
const i64 | value | ||
) |
void ssm_later_i8 | ( | ssm_i8_t * | sv, |
ssm_time_t | then, | ||
const i8 | value | ||
) |
void ssm_later_u16 | ( | ssm_u16_t * | sv, |
ssm_time_t | then, | ||
const u16 | value | ||
) |
void ssm_later_u32 | ( | ssm_u32_t * | sv, |
ssm_time_t | then, | ||
const u32 | value | ||
) |
void ssm_later_u64 | ( | ssm_u64_t * | sv, |
ssm_time_t | then, | ||
const u64 | value | ||
) |
void ssm_later_u8 | ( | ssm_u8_t * | sv, |
ssm_time_t | then, | ||
const u8 | value | ||
) |
|
inlinestatic |
Deallocate an activation record; return to caller if we were the last child.
ssm_time_t ssm_next_event_time | ( | void | ) |
Return the time of the next event in the queue or SSM_NEVER.
Typically used by the platform code that ultimately invokes ssm_tick().
ssm_time_t ssm_now | ( | void | ) |
Return the current model time.
void ssm_reset | ( | ) |
Reset the scheduler.
Set now to 0; clear the event and activation record queues. This does not need to be called before calling ssm_tick() for the first time; the global state automatically starts initialized.
void ssm_schedule | ( | ssm_sv_t * | var, |
ssm_time_t | later | ||
) |
Schedule a future update to a variable.
Add an event to the global event queue for the given variable, replacing any pending event.
var | Variable to schedule: non-NULL |
later | Event time; must be in the future (greater than now) |
void ssm_sensitize | ( | ssm_sv_t * | , |
ssm_trigger_t * | |||
) |
Indicate writing to a variable should trigger a routine.
Add a trigger to a variable's list of triggers. When the scheduled variable is written, the scheduler will run the trigger's routine routine.
If a routine calls ssm_sensitize() on a trigger, it must call ssm_desensitize() on the trigger if it ever calls ssm_leave() to ensure a terminated routine is never inadvertantly triggered.
void ssm_tick | ( | ) |
Run the system for the next scheduled instant.
Typically run by the platform code, not the SSM program per se.
Advance now to the time of the earliest event in the queue, if any.
Remove every event at the head of the event queue scheduled for now, update the variable's current value by calling its (type-specific) update function, and schedule all the triggers in the activation queue.
Remove the activation record in the activation record queue with the lowest priority number and execute its "step" function.
void ssm_trigger | ( | ssm_sv_t * | var, |
ssm_priority_t | priority | ||
) |
Activate routines triggered by a variable.
Call this when a scheduled variable is assigned in the current instant (i.e., not scheduled)
The given priority should be that of the routine doing the update. Instantaneous assignment can only activate lower-priority (i.e., later) routines in the same instant.
var | Variable being assigned |
priority | Priority of the routine doing the assignment. |
void ssm_unschedule | ( | ssm_sv_t * | var | ) |
Unschedule any pending event on a variable.
If there is a pending event on the given variable, remove the event from the queue. Nothing happens if the variable does not have a pending event.
ssm_act_t ssm_top_parent |
An activation record for the parent of the topmost routine.
When you are starting up your SSM system, pass a pointer to this as the parent of your topmost function. E.g., if main
is your topmost function and your enter_main()
function takes its parent as the first argument,
Here, enter_main()
should cause ssm_enter() to be called with