16 #ifdef CONFIG_MEM_TRACE
69 #define SSM_THROW(reason) ssm_throw(reason, __FILE__, __LINE__, __func__)
105 #define SSM_ROOT_PRIORITY 0
114 #define SSM_ROOT_DEPTH (sizeof(ssm_priority_t) * 8)
148 #define ssm_has_children(act) ((act)->children != 0)
178 #ifdef CONFIG_MEM_TRACE
179 #define ssm_enter(si, st, pa, pr, de) \
180 (fprintf(stderr, "%s:%d:ssm_enter(%lu,_,_,_,_,_)\n", __FILE__, __LINE__, \
182 ssm_enter_int((si), (st), (pa), (pr), (de)))
184 #define ssm_enter(si, st, pa, pr, de) \
185 ssm_enter_int((si), (st), (pa), (pr), (de))
291 #define ssm_marshal(v) \
292 (ssm_value_t) { .packed_val = ((v) << 1 | 1) }
299 #define ssm_unmarshal(v) ((v).packed_val >> 1)
306 #define ssm_on_heap(v) (((v).packed_val & 0x1) == 0)
315 #define ssm_is_shared(v) !(ssm_on_heap(v) && ((v).heap_ptr->ref_count == 1))
325 #define ssm_dup(v) (ssm_on_heap(v) ? ssm_dup_unsafe(v) : (v))
338 #define ssm_drop(v) \
340 if (ssm_on_heap(v)) \
341 ssm_drop_unsafe(v); \
352 #define ssm_dup_unsafe(v) ((++(v).heap_ptr->ref_count, (v)))
366 #define ssm_drop_unsafe(v) \
368 if (--(v).heap_ptr->ref_count == 0) \
417 #define SSM_NEVER UINT64_MAX
420 #define SSM_NANOSECOND 1L
422 #define SSM_MICROSECOND (SSM_NANOSECOND * 1000L)
424 #define SSM_MILLISECOND (SSM_MICROSECOND * 1000L)
426 #define SSM_SECOND (SSM_MILLISECOND * 1000L)
428 #define SSM_MINUTE (SSM_SECOND * 60L)
430 #define SSM_HOUR (SSM_MINUTE * 60L)
446 #ifdef CONFIG_MEM_TRACE
447 #define ssm_new_time(t) \
448 (fprintf(stderr, "%s:%d:ssm_new_time()\n", __FILE__, __LINE__), \
451 #define ssm_new_time(t) ssm_new_time_int(t)
464 #define ssm_time_read(v) (container_of((v).heap_ptr, struct ssm_time, mm)->time)
510 #ifdef CONFIG_MEM_TRACE
511 #define ssm_new_adt(fc, tag) \
512 (fprintf(stderr, "%s:%d:ssm_new_adt(%d, %d)\n", __FILE__, __LINE__, (fc), \
514 ssm_new_adt_int((fc), (tag)))
516 #define ssm_new_adt(fc, tag) ssm_new_adt_int((fc), (tag))
536 #define ssm_adt_field(v, i) \
537 (&*container_of((v).heap_ptr, struct ssm_adt1, mm)->fields)[i]
548 (ssm_on_heap(v) ? (v).heap_ptr->info.variant.tag : ssm_unmarshal(v))
551 #define ssm_adt_field_count(v) ((v).heap_ptr->info.variant.count)
558 #define ssm_adt_size(val_count) \
559 (sizeof(struct ssm_adt1) + sizeof(ssm_value_t) * ((val_count)-1))
562 #define ssm_adt_heap_size(v) ssm_adt_size(ssm_adt_field_count(v))
607 #ifdef CONFIG_MEM_TRACE
608 #define ssm_new_sv(v) \
609 (fprintf(stderr, "%s:%d:ssm_new_sv()\n", __FILE__, __LINE__), \
612 #define ssm_new_sv(v) ssm_new_sv_int(v)
623 #define ssm_to_sv(val) container_of((val).heap_ptr, ssm_sv_t, mm)
636 #define ssm_deref(val) (ssm_to_sv(val)->value)
657 #define ssm_assign(var, prio, val) \
660 ssm_drop(ssm_deref(var)); \
661 ssm_sv_assign_unsafe(ssm_to_sv(var), prio, val); \
685 #define ssm_later(var, when, val) \
688 ssm_sv_later_unsafe(ssm_to_sv(var), when, val); \
730 #define ssm_sensitize(var, trig) ssm_sv_sensitize(ssm_to_sv(var), trig)
740 #define ssm_desensitize(trig) ssm_sv_desensitize(trig)
811 #define ssm_closure_arg_count(v) \
812 (container_of((v).heap_ptr, struct ssm_closure1, mm)->mm.info.vector.count)
815 #define ssm_closure_arg_cap(v) \
816 (container_of((v).heap_ptr, struct ssm_closure1, mm)->mm.info.vector.cap)
819 #define ssm_closure_func(v) \
820 (container_of((v).heap_ptr, struct ssm_closure1, mm)->f)
823 #define ssm_closure_argv(v) \
824 (&*container_of((v).heap_ptr, struct ssm_closure1, mm)->argv)
827 #define ssm_closure_arg(v, i) ssm_closure_argv(v)[i]
834 #define ssm_closure_size(val_count) \
835 (sizeof(struct ssm_closure1) + (sizeof(ssm_value_t) * ((val_count)-1)))
838 #define ssm_closure_heap_size(v) ssm_closure_size(ssm_closure_arg_cap(v))
846 #define ssm_closure_push(closure, arg) \
848 ssm_closure_arg(closure, ssm_closure_arg_count(closure)++) = (arg); \
858 #define ssm_closure_pop(closure) \
860 ssm_closure_arg_count(closure)--; \
868 #define ssm_closure_activate(closure, parent, prio, depth, ret) \
869 ssm_activate(ssm_closure_func(closure)(parent, prio, depth, \
870 ssm_closure_argv(closure), ret))
879 #ifdef CONFIG_MEM_TRACE
880 #define ssm_new_closure(f, args) \
881 (fprintf(stderr, "%s:%d:ssm_new_closure(_, %d)\n", __FILE__, __LINE__, \
883 ssm_new_closure_int((f), (args)))
885 #define ssm_new_closure(f, args) ssm_new_closure_int((f), (args))
971 #define ssm_closure_apply_auto(closure, arg, parent, prio, depth, ret) \
974 ssm_closure_apply(closure, arg, parent, prio, depth, ret); \
989 #define ssm_closure_apply_final_auto(closure, arg, parent, prio, depth, ret) \
992 ssm_closure_apply_final(closure, arg, parent, prio, depth, ret); \
996 #define ssm_closure_free(closure) \
997 ssm_mem_free((closure).heap_ptr, \
998 ssm_closure_size(ssm_closure_arg_cap(closure)))
1016 #define ssm_array_len(v) ((v).heap_ptr->info.size)
1019 #define ssm_array_elements(v) \
1020 (&*(container_of((v).heap_ptr, struct ssm_array1, mm)->elements))
1023 #define ssm_array_element(v, i) (ssm_array_elements(v)[i])
1030 #define ssm_array_size(count) \
1031 (sizeof(struct ssm_array1) + sizeof(ssm_value_t) * ((count)-1))
1038 #define ssm_array_heap_size(v) ssm_array_size(ssm_array_len(v))
1050 #ifdef CONFIG_MEM_TRACE
1051 #define ssm_new_array(c) \
1052 (fprintf(stderr,"%s:%d:ssm_new_array(%d)\n", \
1053 __FILE__, __LINE__, (c)), \
1054 ssm_new_array_int(c)
1056 #define ssm_new_array(c) ssm_new_array_int(c)
1067 #define SSM_BLOB_SIZE_SCALE 4
1106 #define ssm_blob_size(size) \
1107 (sizeof(struct ssm_blob1) - SSM_BLOB_SIZE_SCALE + (size))
1114 #define ssm_blob_heap_size(v) \
1115 ssm_blob_size(((v).heap_ptr->info.size) * SSM_BLOB_SIZE_SCALE)
1118 #define ssm_blob_payload(v) \
1119 (&*(container_of((v).heap_ptr, struct ssm_blob1, mm)->payload))
1127 #ifdef CONFIG_MEM_TRACE
1128 #define ssm_new_blob(s) \
1129 (fprintf(stderr, "%s:%d:ssm_new_blob(%lu)\n", __FILE__, __LINE__, (size)), \
1130 ssm_new_blob_int(size))
1132 #define ssm_new_blob(s) ssm_new_blob_int(s)
1196 #define member_type(type, member) __typeof__(((type *)0)->member)
1198 #define member_type(type, member) const void
1226 #define container_of(ptr, type, member) \
1227 ((type *)((char *)(member_type(type, member) *){ptr} - \
1228 offsetof(type, member)))
struct ssm_trigger ssm_trigger_t
Indicates a routine should run when a scheduled variable is written.
uint8_t ssm_depth_t
Index of least significant bit in a group of priorities.
void ssm_leave(ssm_act_t *act, size_t size)
Destroy the activation record of a routine before leaving.
ssm_act_t * ssm_enter_int(size_t size, ssm_stepf_t step, ssm_act_t *parent, ssm_priority_t priority, ssm_depth_t depth)
Allocate and initialize a routine activation record.
struct ssm_act ssm_act_t
Activation record for an SSM routine.
void ssm_stepf_t(struct ssm_act *)
The function that does an instant's work for a routine.
ssm_act_t ssm_top_parent
An activation record for the parent of the top-most routine.
uint32_t ssm_priority_t
Thread priority.
void ssm_activate(ssm_act_t *act)
Schedule a routine to run in the current instant.
ssm_value_t ssm_new_adt_int(uint8_t field_count, uint8_t tag)
Allocate a new ADT object on the heap.
ssm_value_t ssm_new_array_int(uint16_t count)
Allocate an array on the heap.
ssm_value_t ssm_new_blob_int(uint16_t size)
Allocate a blob on the heap.
#define SSM_BLOB_SIZE_SCALE
The size resolution for heap-allocated blobs.
void ssm_closure_apply(ssm_value_t closure, ssm_value_t arg, ssm_act_t *parent, ssm_priority_t prio, ssm_depth_t depth, ssm_value_t *ret)
Apply an argument to a closure.
ssm_value_t ssm_new_closure_int(ssm_func_t f, uint8_t arg_cap)
Allocate a closure on the heap.
ssm_value_t ssm_closure_clone(ssm_value_t closure)
Create a copy of a closure.
void ssm_closure_apply_final(ssm_value_t closure, ssm_value_t arg, ssm_act_t *parent, ssm_priority_t prio, ssm_depth_t depth, ssm_value_t *ret)
Apply an argument to a closure that is used for the last time.
ssm_act_t *(* ssm_func_t)(ssm_act_t *parent, ssm_priority_t prio, ssm_depth_t depth, ssm_value_t *argv, ssm_value_t *ret)
The type signature for all SSM enter functions.
void ssm_throw(ssm_error_t reason, const char *file, int line, const char *func)
Underlying exception handler; must be overridden by each platform.
enum ssm_error ssm_error_t
Error codes indicating reason for failure.
ssm_error
Error codes indicating reason for failure.
@ SSM_EXHAUSTED_ACT_QUEUE
Tried to insert into full activation record queue.
@ SSM_INVALID_MEMORY
Invalid memory layout, e.g., using a pointer where int was expected.
@ SSM_EXHAUSTED_PRIORITY
Tried to exceed available recursion depth.
@ SSM_INTERNAL_ERROR
Reserved for unforeseen, non-user-facing errors.
@ SSM_EXHAUSTED_MEMORY
Could not allocate more memory.
@ SSM_EXHAUSTED_EVENT_QUEUE
Tried to insert into full event queue.
@ SSM_NOT_READY
Not yet ready to perform the requested action.
@ SSM_PLATFORM_ERROR
Start of platform-specific error code range.
@ SSM_INVALID_TIME
Specified invalid time, e.g., scheduled assignment at an earlier time.
ssm_kind
The different kinds of heap objects, enumerated.
void ssm_mem_prealloc(size_t size, size_t num_pages)
Preallocate memory pages to ensure capacity in memory pools.
uint32_t ssm_word_t
Values are 32-bits, the largest supported machine word size.
void ssm_mem_free(void *m, size_t size)
Deallocate memory allocated by ssm_mem_alloc().
void ssm_drops(size_t cnt, ssm_value_t *arr)
Call ssm_drop() on an array of values.
void ssm_drop_final(ssm_value_t v)
Finalize and free a heap object.
void * ssm_mem_alloc(size_t size)
Allocate a contiguous range of memory.
void ssm_dups(size_t cnt, ssm_value_t *arr)
Call ssm_dup() on an array of values.
@ SSM_BLOB_K
Blob of arbitrary data, e.g., ssm_blob1.
@ SSM_ARRAY_K
Array of values, e.g., ssm_array1.
@ SSM_CLOSURE_K
Closure object, e.g., ssm_closure1.
@ SSM_TIME_K
64-bit timestamps, ssm_time_t
@ SSM_SV_K
Scheduled variables, ssm_sv_t.
@ SSM_ADT_K
ADT object, e.g., ssm_adt1.
void ssm_sv_desensitize(ssm_trigger_t *trig)
Desensitize a variable from a trigger.
struct ssm_sv ssm_sv_t
A scheduled variable that supports scheduled updates with triggers.
void ssm_sv_later_unsafe(ssm_sv_t *var, ssm_time_t when, ssm_value_t val)
ssm_later() without automatic reference counting.
ssm_value_t ssm_new_sv_int(ssm_value_t val)
Allocate an ssm_sv on the heap.
void ssm_sv_sensitize(ssm_sv_t *var, ssm_trigger_t *trig)
Sensitize a variable to a trigger.
void ssm_sv_assign_unsafe(ssm_sv_t *var, ssm_priority_t prio, ssm_value_t val)
ssm_assign() without automatic reference counting.
ssm_time_t ssm_now(void)
The current model time.
ssm_value_t ssm_new_time_int(ssm_time_t time)
Allocate a ssm_time on the heap.
uint64_t ssm_time_t
Absolute time; never to overflow.
Activation record for an SSM routine.
ssm_priority_t priority
Execution priority; lower goes first.
uint16_t children
Number of running child threads.
ssm_depth_t depth
Index of the LSB in our priority.
struct ssm_act * caller
Activation record of caller.
ssm_stepf_t * step
C function for running this continuation.
uint16_t pc
Stored "program counter" for the function.
bool scheduled
True when in the schedule queue.
The struct template of a heap-allocated ADT object.
ssm_value_t fields[1]
Array of ADT object fields.
struct ssm_mm mm
Variant-flavored memory management header.
The struct template of a heap-allocated array of values.
ssm_value_t elements[1]
Elements of the heap-allocated array.
struct ssm_mm mm
Size-flavored memory management header.
The struct template of a heap-allocated blob.
char payload[SSM_BLOB_SIZE_SCALE]
Payload of heap-allocated blob.
struct ssm_mm mm
Size-flavored memory management header.
The struct template of a heap-allocated closure object.
ssm_func_t f
Enter function pointer.
ssm_value_t argv[1]
An array of arguments.
struct ssm_mm mm
Memory management header.
The memory management metadata "header" for heap-allocated objects.
uint8_t cap
Which variant is inhabited by this object.
uint8_t count
Number of ssm_value_t values in payload.
struct ssm_mm::@0::@1 variant
uint8_t tag
Which variant is inhabited by this object.
union ssm_mm::@0 info
Three "flavors" of information embedded in the header.
uint8_t ref_count
The number of references to this object.
uint8_t kind
The ssm_kind of object this is.
struct ssm_mm::@0::@2 vector
A scheduled variable that supports scheduled updates with triggers.
ssm_time_t later_time
When the variable should be next updated.
ssm_time_t last_updated
When the variable was last updated.
ssm_value_t value
Current value.
ssm_trigger_t * triggers
List of sensitive continuations.
ssm_value_t later_value
Buffered value for delayed assignment.
Heap-allocated time values.
ssm_time_t time
Time value payload.
struct ssm_mm mm
Embedded memory management header.
Indicates a routine should run when a scheduled variable is written.
struct ssm_trigger ** prev_ptr
Pointer to self in previous element.
struct ssm_act * act
Routine triggered by this variable.
struct ssm_trigger * next
Next sensitive trigger, if any.
SSM values are either "packed" values or heap-allocated.
struct ssm_mm * heap_ptr
Pointer to a heap-allocated object.
ssm_word_t packed_val
Packed value.