ssm
Runtime Library for the Sparse Synchronous Model
Data Structures | Macros | Typedefs | Functions | Variables
The SSM Runtime

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_tssm_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...
 

Detailed Description

Macro Definition Documentation

◆ container_of

#define container_of (   ptr,
  type,
  member 
)
Value:
((type *)((char *)(member_type(type, member) *){ptr} - \
offsetof(type, member)))
#define member_type(type, member)
Implementation of container_of that falls back to ISO C99 when GNU C is not available (from https://s...
Definition: ssm.h:401

◆ member_type

#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)

◆ SSM_ACT_FIELDS

#define SSM_ACT_FIELDS
Value:
ssm_stepf_t *step; \
ssm_act_t *caller; \
uint16_t pc; \
uint16_t children; \
ssm_priority_t priority; \
ssm_depth_t depth; \
bool scheduled
void ssm_stepf_t(struct ssm_act *)
The function that does an instant's work for a routine.
Definition: ssm.h:131

"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;

◆ SSM_ACT_FREE

#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.

◆ SSM_ACT_MALLOC

#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

◆ SSM_DECLARE_SV_SCALAR

#define SSM_DECLARE_SV_SCALAR (   payload_t)
Value:
typedef struct { \
ssm_sv_t sv; \
payload_t value; /* Current value */ \
payload_t later_value; /* Buffered value */ \
} ssm_##payload_t##_t; \
void ssm_assign_##payload_t(ssm_##payload_t##_t *sv, ssm_priority_t prio, \
const payload_t value); \
void ssm_later_##payload_t(ssm_##payload_t##_t *sv, ssm_time_t then, \
const payload_t value); \
void ssm_initialize_##payload_t(ssm_##payload_t##_t *v);
uint64_t ssm_time_t
Absolute time; never to overflow.
Definition: ssm.h:100
uint32_t ssm_priority_t
Thread priority.
Definition: ssm.h:112

◆ SSM_DEFINE_SV_SCALAR

#define SSM_DEFINE_SV_SCALAR (   payload_t)
Value:
static void ssm_update_##payload_t(ssm_sv_t *sv) { \
ssm_##payload_t##_t *v = container_of(sv, ssm_##payload_t##_t, sv); \
v->value = v->later_value; \
} \
void ssm_assign_##payload_t(ssm_##payload_t##_t *v, ssm_priority_t prio, \
const payload_t value) { \
v->value = value; \
v->sv.last_updated = ssm_now(); \
ssm_trigger(&v->sv, prio); \
} \
void ssm_later_##payload_t(ssm_##payload_t##_t *v, ssm_time_t then, \
const payload_t value) { \
v->later_value = value; \
ssm_schedule(&v->sv, then); \
} \
void ssm_initialize_##payload_t(ssm_##payload_t##_t *v) { \
ssm_initialize(&v->sv, ssm_update_##payload_t); \
}
uint64_t ssm_time_t
Absolute time; never to overflow.
Definition: ssm.h:100
A variable that may have scheduled updates and triggers.
Definition: ssm.h:206
#define container_of(ptr, type, member)
Definition: ssm.h:403
ssm_time_t ssm_now(void)
Return the current model time.
Definition: ssm-scheduler.c:182
uint32_t ssm_priority_t
Thread priority.
Definition: ssm.h:112

◆ SSM_HOUR

#define SSM_HOUR   (SSM_SECOND*3600L)

Ticks per hour.

◆ ssm_later_event

#define ssm_later_event (   var,
  then 
)    ssm_schedule((var), (then))

◆ SSM_MICROSECOND

#define SSM_MICROSECOND   (SSM_SECOND/1000000L)

Ticks per microsecond.

◆ SSM_MILLISECOND

#define SSM_MILLISECOND   (SSM_SECOND/1000L)

Ticks per millisecond.

◆ SSM_MINUTE

#define SSM_MINUTE   (SSM_SECOND*60L)

Ticks per minute.

◆ SSM_NANOSECOND

#define SSM_NANOSECOND   (SSM_SECOND/1000000000L)

Ticks per nanosecond.

◆ SSM_NEVER

#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

◆ SSM_RESOURCES_EXHAUSTED

#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.

◆ SSM_ROOT_DEPTH

#define SSM_ROOT_DEPTH   (sizeof(ssm_priority_t) * 8)

The depth at the entry point of an SSM program.

◆ SSM_ROOT_PRIORITY

#define SSM_ROOT_PRIORITY   0

The priority for the entry point of an SSM program.

◆ SSM_SECOND

#define SSM_SECOND   1000000000L

Ticks in a second.

Override this according to your platform

Typedef Documentation

◆ i16

typedef int16_t i16

16-bit Signed Integer

◆ i32

typedef int32_t i32

32-bit Signed Integer

◆ i64

typedef int64_t i64

64-bit Signed Integer

◆ i8

typedef int8_t i8

8-bit Signed Integer

◆ ssm_act_t

typedef struct ssm_act ssm_act_t

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

◆ ssm_depth_t

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.

◆ ssm_event_t

◆ ssm_priority_t

typedef uint32_t ssm_priority_t

Thread priority.

Lower numbers execute first in an instant

◆ ssm_stepf_t

typedef void ssm_stepf_t(struct ssm_act *)

The function that does an instant's work for a routine.

◆ ssm_sv_t

typedef struct ssm_sv ssm_sv_t

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.

◆ ssm_time_t

typedef uint64_t ssm_time_t

Absolute time; never to overflow.

◆ ssm_trigger_t

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.

◆ u16

typedef uint16_t u16

16-bit Unsigned Integer

◆ u32

typedef uint32_t u32

32-bit Unsigned Integer

◆ u64

typedef uint64_t u64

64-bit Unsigned Integer

◆ u8

typedef uint8_t u8

8-bit Unsigned Integer

Function Documentation

◆ ssm_activate()

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.

◆ ssm_assign_bool()

void ssm_assign_bool ( ssm_bool_t sv,
ssm_priority_t  prio,
const bool  value 
)

◆ ssm_assign_event()

void ssm_assign_event ( ssm_event_t var,
ssm_priority_t  prio 
)

◆ ssm_assign_i16()

void ssm_assign_i16 ( ssm_i16_t sv,
ssm_priority_t  prio,
const i16  value 
)

◆ ssm_assign_i32()

void ssm_assign_i32 ( ssm_i32_t sv,
ssm_priority_t  prio,
const i32  value 
)

◆ ssm_assign_i64()

void ssm_assign_i64 ( ssm_i64_t sv,
ssm_priority_t  prio,
const i64  value 
)

◆ ssm_assign_i8()

void ssm_assign_i8 ( ssm_i8_t sv,
ssm_priority_t  prio,
const i8  value 
)

◆ ssm_assign_u16()

void ssm_assign_u16 ( ssm_u16_t sv,
ssm_priority_t  prio,
const u16  value 
)

◆ ssm_assign_u32()

void ssm_assign_u32 ( ssm_u32_t sv,
ssm_priority_t  prio,
const u32  value 
)

◆ ssm_assign_u64()

void ssm_assign_u64 ( ssm_u64_t sv,
ssm_priority_t  prio,
const u64  value 
)

◆ ssm_assign_u8()

void ssm_assign_u8 ( ssm_u8_t sv,
ssm_priority_t  prio,
const u8  value 
)

◆ ssm_call()

static void ssm_call ( ssm_act_t act)
inlinestatic

Execute a routine immediately.

◆ ssm_desensitize()

void ssm_desensitize ( ssm_trigger_t )

Disable a sensitized routine.

Remove the trigger from its variable. Only call this on a previously-sensitized trigger.

◆ ssm_enter()

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 
)
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.

Parameters
bytessize of the activation record, >0
stepPointer to "step" function, non-NULL
parentActivation record of caller, non-NULL
priorityPriority: must be no less than parent's
depthDepth; used if this routine has children

◆ ssm_event_on()

bool ssm_event_on ( ssm_sv_t var)

Return true if there is an event on the given variable in the current instant.

Parameters
varVariable: must be non-NULL

◆ ssm_initialize()

void ssm_initialize ( ssm_sv_t var,
void(*)(ssm_sv_t *)  update 
)

Initialize a scheduled variable.

Call this to initialize the contents of a newly allocated scheduled variable, e.g., after ssm_enter()

◆ ssm_initialize_bool()

void ssm_initialize_bool ( ssm_bool_t v)

◆ ssm_initialize_event()

void ssm_initialize_event ( ssm_event_t )

◆ ssm_initialize_i16()

void ssm_initialize_i16 ( ssm_i16_t v)

◆ ssm_initialize_i32()

void ssm_initialize_i32 ( ssm_i32_t v)

◆ ssm_initialize_i64()

void ssm_initialize_i64 ( ssm_i64_t v)

◆ ssm_initialize_i8()

void ssm_initialize_i8 ( ssm_i8_t v)

◆ ssm_initialize_u16()

void ssm_initialize_u16 ( ssm_u16_t v)

◆ ssm_initialize_u32()

void ssm_initialize_u32 ( ssm_u32_t v)

◆ ssm_initialize_u64()

void ssm_initialize_u64 ( ssm_u64_t v)

◆ ssm_initialize_u8()

void ssm_initialize_u8 ( ssm_u8_t v)

◆ ssm_later_bool()

void ssm_later_bool ( ssm_bool_t sv,
ssm_time_t  then,
const bool  value 
)

◆ ssm_later_i16()

void ssm_later_i16 ( ssm_i16_t sv,
ssm_time_t  then,
const i16  value 
)

◆ ssm_later_i32()

void ssm_later_i32 ( ssm_i32_t sv,
ssm_time_t  then,
const i32  value 
)

◆ ssm_later_i64()

void ssm_later_i64 ( ssm_i64_t sv,
ssm_time_t  then,
const i64  value 
)

◆ ssm_later_i8()

void ssm_later_i8 ( ssm_i8_t sv,
ssm_time_t  then,
const i8  value 
)

◆ ssm_later_u16()

void ssm_later_u16 ( ssm_u16_t sv,
ssm_time_t  then,
const u16  value 
)

◆ ssm_later_u32()

void ssm_later_u32 ( ssm_u32_t sv,
ssm_time_t  then,
const u32  value 
)

◆ ssm_later_u64()

void ssm_later_u64 ( ssm_u64_t sv,
ssm_time_t  then,
const u64  value 
)

◆ ssm_later_u8()

void ssm_later_u8 ( ssm_u8_t sv,
ssm_time_t  then,
const u8  value 
)

◆ ssm_leave()

static void ssm_leave ( ssm_act_t act,
size_t  bytes 
)
inlinestatic

Deallocate an activation record; return to caller if we were the last child.

◆ ssm_next_event_time()

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_now()

ssm_time_t ssm_now ( void  )

Return the current model time.

◆ ssm_reset()

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.

◆ ssm_schedule()

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.

Parameters
varVariable to schedule: non-NULL
laterEvent time; must be in the future (greater than now)

◆ ssm_sensitize()

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.

◆ ssm_tick()

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.

◆ ssm_trigger()

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.

Parameters
varVariable being assigned
priorityPriority of the routine doing the assignment.

◆ ssm_unschedule()

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.

Variable Documentation

◆ ssm_top_parent

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,

main_act_t *enter_main(ssm_act_t *, ssm_priority_t, ssm_depth_t);
void step_main(ssm_act_t *act);

Here, enter_main() should cause ssm_enter() to be called with

ssm_enter(sizeof(main_act_t), step_main, &ssm_top_parent, SSM_ROOT_PRIORITY, SSM_ROOT_DEPTH)