ssm  0.0.2
Runtime Library for the Sparse Synchronous Model
ssm-mem.c
Go to the documentation of this file.
1 /** @file ssm-mem.c
2  * @brief SSM runtime memory management and allocation.
3  *
4  * @author John Hui (j-hui)
5  * @author Stephen Edwards (sedwards-lab)
6  * @author Daniel Scanteianu (Scanteianu)
7  */
8 #include <assert.h>
9 #include <ssm-internal.h>
10 #include <ssm.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 
14 /** @brief (The beginning of) a block of memory.
15  *
16  * The size of each block varies depending on which memory pool it resides in.
17  * When a block is being used (allocated), @a block_buf effectively gives
18  * a pointer to the beginning that block that can be indexed into.
19  *
20  * When a block is not being used, it is maintained in a <em>free list</em>.
21  * If it is not at the head of the free list, then it is pointed to by the @a
22  * free_list_next field of some other block_t, while its own @a free_list_next
23  * points to the next block in the free list. To avoid initializing the @a
24  * free_list_next fields of "fresh" blocks, when @a free_list_next is
25  * #UNINITIALIZED_FREE_BLOCK, the next free block contiguously follows the
26  * current block in memory. The last free block points to #END_OF_FREELIST.
27  */
28 typedef union block {
29  union block *free_list_next; /**< Pointer to the next block. */
30  uint8_t block_buf[1]; /**< Variable-size buffer of the block. */
32 
33 /** @brief The number of blocks in each memory page. */
34 #define BLOCKS_PER_PAGE (SSM_MEM_PAGE_SIZE / sizeof(block_t))
35 
36 /** @brief A "pointer" that points to the next contiguous block in memory. */
37 #define UNINITIALIZED_FREE_BLOCK ((block_t *)0x0)
38 
39 /** @brief Sentinel value indicating the end of the free list. */
40 #define END_OF_FREELIST ((block_t *)0x42)
41 
42 /** @brief A memory pool, which maintains a free list.
43  *
44  * The size of blocks maintained by a memory pool is implicit in its position
45  * within #mem_pools.
46  */
47 struct mem_pool {
48  block_t *free_list_head; /**< Pointer to the beginning of the free list. */
49 };
50 
51 /** @brief Memory pools from #SSM_MEM_POOL_MIN to #SSM_MEM_POOL_MAX. */
53 
54 /** @brief Page allocation handler, set by ssm_mem_init(). */
55 static void *(*alloc_page)(void);
56 
57 /** @brief Large memory allocation handler, set by ssm_mem_init(). */
58 static void *(*alloc_mem)(size_t size);
59 
60 /** @brief Large memory release handler, set by ssm_mem_init(). */
61 static void (*free_mem)(void *mem, size_t size);
62 
63 /** @brief Find the memory pool for some arbitrary size.
64  *
65  * Tries to find the smallest memory pool that will fit a block of @a size.
66  * Returns #SSM_MEM_POOL_COUNT if no such pool exists, i.e., if @a size is
67  * greater than #SSM_MEM_POOL_MAX.
68  *
69  * Since #SSM_MEM_POOL_COUNT is a (small) compile-time constant, this linear
70  * search is effectively contant time.
71  *
72  * @param size the block size whose memory pool we are looking for.
73  * @returns index to the memory pool, or #SSM_MEM_POOL_COUNT otherwise.
74  */
75 static inline size_t find_pool_size(size_t size) {
76  for (size_t pool_idx = 0; pool_idx < SSM_MEM_POOL_COUNT; pool_idx++)
77  if (size <= SSM_MEM_POOL_SIZE(pool_idx))
78  return pool_idx;
79  return SSM_MEM_POOL_COUNT;
80 }
81 
82 static inline block_t *find_next_block(block_t *block, size_t pool_size) {
84  return block + pool_size / sizeof(block_t);
85  else
86  return block->free_list_next;
87 }
88 
89 #ifdef CONFIG_MEM_STATS
90 /** @brief Tracks how many pages have been allocated by alloc_pool().
91  *
92  * @note Define CONFIG_MEM_STATS to enable this.
93  */
94 static size_t num_pages_allocated = 0;
95 static size_t live_objects = 0;
96 static size_t pages_allocated[SSM_MEM_POOL_COUNT] = {0};
97 static size_t objects_allocated = 0;
98 static size_t objects_freed = 0;
99 #endif
100 
101 #ifndef CONFIG_MALLOC_HEAP
102 /** @brief Allocate a new block for a memory pool.
103  *
104  * Calls alloc_page() to allocate a new zero-initialized page for the memory
105  * pool, and adds it to the corresponding memory pool with stack discipline.
106  * The last block of the free list is pointed to the old head of the free list.
107  *
108  * Constant time (not counting what alloc_page() does).
109  *
110  * @param p the index of the memory pool.
111  */
112 static inline void alloc_pool(size_t p) {
113  block_t *new_page = alloc_page();
114  SSM_ASSERT(END_OF_FREELIST < new_page);
115 
116 #ifdef CONFIG_MEM_STATS
118  pages_allocated[p]++;
119 #endif
120 
121  struct mem_pool *pool = &mem_pools[p];
122  size_t last_block = BLOCKS_PER_PAGE - SSM_MEM_POOL_SIZE(p) / sizeof(block_t);
123  new_page[last_block].free_list_next = pool->free_list_head;
124  pool->free_list_head = new_page;
125 
126 #ifdef USE_VALGRIND
127  // Mark as NOACCESS; nothing should touch this memory until it is allocated.
128  VALGRIND_MAKE_MEM_NOACCESS(new_page, SSM_MEM_PAGE_SIZE);
129 
130  // Label this page with a human-readable name, for memory error reporting.
131  VALGRIND_CREATE_BLOCK(new_page, SSM_MEM_PAGE_SIZE, "SSM memory pool page");
132 #endif
133 }
134 #endif /* ifndef CONFIG_MALLOC_HEAP */
135 
136 void ssm_mem_init(void *(*alloc_page_handler)(void),
137  void *(*alloc_mem_handler)(size_t),
138  void (*free_mem_handler)(void *, size_t)) {
139  alloc_page = alloc_page_handler;
140  alloc_mem = alloc_mem_handler;
141  free_mem = free_mem_handler;
142 
143  for (size_t p = 0; p < SSM_MEM_POOL_COUNT; p++) {
145  }
146 
147 #ifdef USE_VALGRIND
148  // Ask Valgrind to checkpoint the amount of memory allocated so far.
149  VALGRIND_PRINTF("Performing leak check at memory initialization.\n");
150  VALGRIND_PRINTF("(Checkpoints how much memory is allocated at init time.)\n");
151  VALGRIND_PRINTF("\n");
152  VALGRIND_DO_QUICK_LEAK_CHECK;
153 #endif
154 }
155 
156 void ssm_mem_destroy(void (*free_page_handler)(void *)) {
157  // TODO: call free_page_handler on all superblocks in each mem pool.
158  // for (size_t p = 0; p < SSM_MEM_POOL_COUNT; p++) {
159  // if (mem_pools[p].free_list_head != END_OF_FREELIST) {
160  // }
161  // }
162 
163 #ifdef USE_VALGRIND
164  // Report how much memory has been leaked since the checkpoint in
165  // ssm_mem_init().
166  VALGRIND_PRINTF("About to destroy SSM allocator. Performing leak check.\n");
167  VALGRIND_PRINTF("(Note that leaks from malloc() may be false positives.)\n");
168  VALGRIND_PRINTF("\n");
169  VALGRIND_DO_ADDED_LEAK_CHECK;
170 #endif
171 }
172 
173 #ifndef CONFIG_MALLOC_HEAP
174 void ssm_mem_prealloc(size_t size, size_t num_pages) {
175  size_t p = find_pool_size(size);
176  if (p >= SSM_MEM_POOL_COUNT)
177  return;
178  for (size_t i = 0; i < num_pages; i++)
179  alloc_pool(p);
180 }
181 #endif
182 
183 void *ssm_mem_alloc(size_t size) {
184 
185 #ifdef CONFIG_MEM_STATS
187  live_objects++;
188 #endif
189 
190  void *m;
191 
192 #ifdef CONFIG_MALLOC_HEAP
193  m = malloc(size);
194 #else
195 
196  size_t p = find_pool_size(size);
197  if (p >= SSM_MEM_POOL_COUNT) {
198  m = alloc_mem(size);
199  } else {
200  struct mem_pool *pool = &mem_pools[p];
201 
202  if (pool->free_list_head == END_OF_FREELIST)
203  alloc_pool(p);
204 
205  m = pool->free_list_head->block_buf;
206 
207 #ifdef USE_VALGRIND
208  // Tell Valgrind that we have allocated m as a chunk of pool.
209  //
210  // The memory range [m..m+size] is now considered DEFINED.
211  VALGRIND_MALLOCLIKE_BLOCK(m, size, 0, 1);
212 #endif
213 
214  pool->free_list_head =
216 
217 #ifdef USE_VALGRIND
218  // Make the memory range [m..m+size] undefined, because the caller should
219  // not rely on allocated chunks being defined.
220  VALGRIND_MAKE_MEM_UNDEFINED(m, size);
221 #endif
222  }
223 
224 #endif /* CONFIG_MALLOC_HEAP */
225 
226 #ifdef CONFIG_MEM_TRACE
227  fprintf(stderr, "%p = ssm_mem_alloc(%lu)\n", m, size);
228 #endif
229 
230  return m;
231 }
232 
233 void ssm_mem_free(void *m, size_t size) {
234 
235 #ifdef CONFIG_MEM_TRACE
236  fprintf(stderr, "%p ssm_mem_free(%lu)\n", m, size);
237 #endif
238 
239 #ifdef CONFIG_MEM_STATS
240  live_objects--;
241  objects_freed++;
242 #endif
243 
244 #ifdef CONFIG_MALLOC_HEAP
245  free(m);
246 #else
247  size_t p = find_pool_size(size);
248  if (p >= SSM_MEM_POOL_COUNT) {
249  free_mem(m, size);
250  return;
251  }
252 
253  struct mem_pool *pool = &mem_pools[p];
254 
255  block_t *new_head = m;
256  new_head->free_list_next = pool->free_list_head;
257  pool->free_list_head = new_head;
258 
259 #ifdef USE_VALGRIND
260  // Tell Valgrind that we have freed m.
261  VALGRIND_FREELIKE_BLOCK(m, 0);
262 #endif
263 #endif /* CONFIG_MALLOC_HEAP */
264 }
265 
267  struct ssm_time *t = ssm_mem_alloc(sizeof(struct ssm_sv));
268  t->mm.ref_count = 1;
269  t->mm.kind = SSM_TIME_K;
270  t->time = time;
271  return (ssm_value_t){.heap_ptr = &t->mm};
272 }
273 
274 ssm_value_t ssm_new_adt_int(uint8_t field_count, uint8_t tag) {
275  struct ssm_mm *mm = ssm_mem_alloc(ssm_adt_size(field_count));
276  mm->ref_count = 1;
277  mm->kind = SSM_ADT_K;
278  mm->info.variant.count = field_count;
279  mm->info.variant.tag = tag;
280  return (ssm_value_t){.heap_ptr = mm};
281 }
282 
284  struct ssm_sv *sv = ssm_mem_alloc(sizeof(struct ssm_sv));
285  sv->mm.ref_count = 1;
286  sv->mm.kind = SSM_SV_K;
287  sv->later_time = SSM_NEVER;
288  sv->last_updated = SSM_NEVER;
289  sv->triggers = NULL;
290  sv->value = val;
291  return (ssm_value_t){.heap_ptr = &sv->mm};
292 }
293 
295  struct ssm_closure1 *closure = container_of(
296  ssm_mem_alloc(ssm_closure_size(arg_cap)), struct ssm_closure1, mm);
297  closure->mm.ref_count = 1;
298  closure->mm.kind = SSM_CLOSURE_K;
299  closure->mm.info.vector.count = 0;
300  closure->mm.info.vector.cap = arg_cap;
301  closure->f = f;
302  return (ssm_value_t){.heap_ptr = &closure->mm};
303 }
304 
306  struct ssm_mm *mm = ssm_mem_alloc(ssm_array_size(elems));
307  mm->ref_count = 1;
308  mm->kind = SSM_ARRAY_K;
309  mm->info.size = elems;
310  return (ssm_value_t){.heap_ptr = mm};
311 }
312 
314  uint16_t scaled_size = // ceiling(size / SSM_BLOB_SIZE_SCALE)
316 
317  struct ssm_mm *mm =
319  mm->ref_count = 1;
320  mm->kind = SSM_BLOB_K;
321  mm->info.size = scaled_size;
322  return (ssm_value_t){.heap_ptr = mm};
323 }
324 
326  size_t size = 0;
327  switch (v.heap_ptr->kind) {
328  case SSM_TIME_K:
329  size = sizeof(struct ssm_time);
330  break;
331  case SSM_ADT_K:
332  size = ssm_adt_heap_size(v);
333  for (size_t i = 0; i < ssm_adt_field_count(v); i++)
334  ssm_drop(ssm_adt_field(v, i));
335  break;
336  case SSM_SV_K:
337  size = sizeof(struct ssm_sv);
339  ssm_drop(ssm_to_sv(v)->value);
340  if (ssm_to_sv(v)->later_time != SSM_NEVER)
342  break;
343  case SSM_CLOSURE_K:
344  size = ssm_closure_heap_size(v);
345  for (size_t i = 0; i < ssm_closure_arg_count(v); i++)
346  ssm_drop(ssm_closure_arg(v, i));
347  break;
348  case SSM_ARRAY_K:
349  size = ssm_array_heap_size(v);
350  for (size_t i = 0; i < ssm_array_len(v); i++)
352  break;
353  case SSM_BLOB_K:
354  size = ssm_blob_heap_size(v);
355  break;
356  default:
357  SSM_THROW(SSM_INTERNAL_ERROR); // Unknown object kind
358  break;
359  }
360  ssm_mem_free(v.heap_ptr, size);
361 }
362 
363 // These are functions rather than macros to limit code size.
364 // I anticipate few valuable opportunities for the optimizer to inline
365 // code, since it's quite difficult to know ahead of time how many
366 // arguments are already contained in a closure.
367 void ssm_dups(size_t cnt, ssm_value_t *arr) {
368  for (size_t i = 0; i < cnt; i++)
369  ssm_dup(arr[i]);
370 }
371 
372 void ssm_drops(size_t cnt, ssm_value_t *arr) {
373  for (size_t i = 0; i < cnt; i++)
374  ssm_drop(arr[i]);
375 }
376 
377 #ifdef CONFIG_MEM_STATS
379  SSM_ASSERT(stats != NULL);
380 
381  stats->sizeof_ssm_mm = sizeof(struct ssm_mm);
382  stats->page_size = SSM_MEM_PAGE_SIZE;
385  stats->objects_freed = objects_freed;
386  stats->live_objects = live_objects;
387 
389 
390  for (size_t i = 0; i < SSM_MEM_POOL_COUNT; i++) {
391  size_t pool_size = SSM_MEM_POOL_SIZE(i);
392  stats->pool[i].block_size = pool_size;
393  stats->pool[i].pages_allocated = pages_allocated[i];
394  size_t n = 0;
396  while (block != END_OF_FREELIST) {
397  n++;
398  block = find_next_block(block, pool_size);
399  }
400  stats->pool[i].free_list_length = n;
401  }
402 }
403 #endif /* CONFIG_MEM_STATS */
#define ssm_adt_heap_size(v)
Compute the size of an ADT already allocated on the heap.
Definition: ssm.h:562
#define ssm_adt_field(v, i)
Access the field of an ADT object.
Definition: ssm.h:536
#define ssm_adt_size(val_count)
Compute the size of a heap-allocated ADT.
Definition: ssm.h:558
ssm_value_t ssm_new_adt_int(uint8_t field_count, uint8_t tag)
Allocate a new ADT object on the heap.
Definition: ssm-mem.c:274
#define ssm_adt_field_count(v)
Obtain number of fields in the ADT pointed by v.
Definition: ssm.h:551
#define ssm_array_element(v, i)
Obtain pointer to the ith element of the array pointed by v.
Definition: ssm.h:1023
#define ssm_array_len(v)
The length of an array pointed by v.
Definition: ssm.h:1016
#define ssm_array_heap_size(v)
Compute the size an array in the heap from an ssm_value_t.
Definition: ssm.h:1038
#define ssm_array_size(count)
Compute the size of an array with its header.
Definition: ssm.h:1030
ssm_value_t ssm_new_array_int(uint16_t elems)
Allocate an array on the heap.
Definition: ssm-mem.c:305
ssm_value_t ssm_new_blob_int(uint16_t size)
Allocate a blob on the heap.
Definition: ssm-mem.c:313
#define ssm_blob_size(size)
Compute the size of a blob with its header.
Definition: ssm.h:1106
#define ssm_blob_heap_size(v)
Compute the size a blob in the heap.
Definition: ssm.h:1114
#define SSM_BLOB_SIZE_SCALE
The size resolution for heap-allocated blobs.
Definition: ssm.h:1067
ssm_value_t ssm_new_closure_int(ssm_func_t f, uint8_t arg_cap)
Allocate a closure on the heap.
Definition: ssm-mem.c:294
#define ssm_closure_arg_count(v)
Obtain the number of argument values owned by a closure.
Definition: ssm.h:811
#define ssm_closure_heap_size(v)
Compute the size of a closure already allocated on the heap.
Definition: ssm.h:838
#define ssm_closure_size(val_count)
Compute the size of a closure object.
Definition: ssm.h:834
#define ssm_closure_arg(v, i)
Obtain the ith argument of a closure.
Definition: ssm.h:827
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.
Definition: ssm.h:783
#define SSM_ASSERT(cond)
Throw an internal error.
Definition: ssm-internal.h:23
#define SSM_THROW(reason)
Terminate due to a non-recoverable error, with a specified reason.
Definition: ssm.h:69
@ SSM_INTERNAL_ERROR
Reserved for unforeseen, non-user-facing errors.
Definition: ssm.h:38
void ssm_mem_prealloc(size_t size, size_t num_pages)
Preallocate memory pages to ensure capacity in memory pools.
void ssm_mem_free(void *m, size_t size)
Deallocate memory allocated by ssm_mem_alloc().
Definition: ssm-mem.c:233
void ssm_mem_destroy(void(*free_page_handler)(void *))
Tears down the underlying allocator system.
Definition: ssm-mem.c:156
#define SSM_MEM_POOL_COUNT
Number of memory pools.
Definition: ssm-internal.h:213
void ssm_drops(size_t cnt, ssm_value_t *arr)
Call ssm_drop() on an array of values.
Definition: ssm-mem.c:372
#define ssm_dup(v)
Duplicate a possible heap reference, incrementing its ref count.
Definition: ssm.h:325
#define SSM_MEM_POOL_SIZE(pool)
Compute the size of a memory pool.
Definition: ssm-internal.h:227
#define SSM_MEM_PAGE_SIZE
The size of a memory page; must be greater than SSM_MEM_POOL_MAX.
Definition: ssm-internal.h:241
#define ssm_drop(v)
Drop a reference to a possible heap item, and free it if necessary.
Definition: ssm.h:338
void ssm_drop_final(ssm_value_t v)
Finalize and free a heap object.
Definition: ssm-mem.c:325
void ssm_mem_statistics_collect(ssm_mem_statistics_t *stats)
Collect and return statistics about the heap.
Definition: ssm-mem.c:378
void * ssm_mem_alloc(size_t size)
Allocate a contiguous range of memory.
Definition: ssm-mem.c:183
void ssm_dups(size_t cnt, ssm_value_t *arr)
Call ssm_dup() on an array of values.
Definition: ssm-mem.c:367
void ssm_mem_init(void *(*alloc_page_handler)(void), void *(*alloc_mem_handler)(size_t), void(*free_mem_handler)(void *, size_t))
Initializes the underlying allocator system.
Definition: ssm-mem.c:136
@ SSM_BLOB_K
Blob of arbitrary data, e.g., ssm_blob1.
Definition: ssm.h:283
@ SSM_ARRAY_K
Array of values, e.g., ssm_array1.
Definition: ssm.h:282
@ SSM_CLOSURE_K
Closure object, e.g., ssm_closure1.
Definition: ssm.h:281
@ SSM_TIME_K
64-bit timestamps, ssm_time_t
Definition: ssm.h:278
@ SSM_SV_K
Scheduled variables, ssm_sv_t.
Definition: ssm.h:280
@ SSM_ADT_K
ADT object, e.g., ssm_adt1.
Definition: ssm.h:279
void ssm_unschedule(ssm_sv_t *var)
Unschedule any pending events on a variable.
#define ssm_to_sv(val)
Retrieve ssm_sv pointer pointed to by an ssm_value_t.
Definition: ssm.h:623
ssm_value_t ssm_new_sv_int(ssm_value_t val)
Allocate an ssm_sv on the heap.
Definition: ssm-mem.c:283
#define SSM_NEVER
Time indicating something will never happen.
Definition: ssm.h:417
ssm_value_t ssm_new_time_int(ssm_time_t time)
Allocate a ssm_time on the heap.
Definition: ssm-mem.c:266
uint64_t ssm_time_t
Absolute time; never to overflow.
Definition: ssm.h:399
#define container_of(ptr, type, member)
Obtain the pointer to an outer, enclosing struct.
Definition: ssm.h:1226
The internal interface of the SSM runtime.
struct mem_pool mem_pools[SSM_MEM_POOL_COUNT]
Memory pools from SSM_MEM_POOL_MIN to SSM_MEM_POOL_MAX.
Definition: ssm-mem.c:52
static void *(* alloc_page)(void)
Page allocation handler, set by ssm_mem_init().
Definition: ssm-mem.c:55
static size_t live_objects
Definition: ssm-mem.c:95
static size_t objects_allocated
Definition: ssm-mem.c:97
#define BLOCKS_PER_PAGE
The number of blocks in each memory page.
Definition: ssm-mem.c:34
#define UNINITIALIZED_FREE_BLOCK
A "pointer" that points to the next contiguous block in memory.
Definition: ssm-mem.c:37
static size_t pages_allocated[SSM_MEM_POOL_COUNT]
Definition: ssm-mem.c:96
static block_t * find_next_block(block_t *block, size_t pool_size)
Definition: ssm-mem.c:82
static size_t find_pool_size(size_t size)
Find the memory pool for some arbitrary size.
Definition: ssm-mem.c:75
static void(* free_mem)(void *mem, size_t size)
Large memory release handler, set by ssm_mem_init().
Definition: ssm-mem.c:61
#define END_OF_FREELIST
Sentinel value indicating the end of the free list.
Definition: ssm-mem.c:40
static size_t num_pages_allocated
Tracks how many pages have been allocated by alloc_pool().
Definition: ssm-mem.c:94
union block block_t
(The beginning of) a block of memory.
static size_t objects_freed
Definition: ssm-mem.c:98
static void *(* alloc_mem)(size_t size)
Large memory allocation handler, set by ssm_mem_init().
Definition: ssm-mem.c:58
Interface to the SSM runtime.
A memory pool, which maintains a free list.
Definition: ssm-mem.c:47
block_t * free_list_head
Pointer to the beginning of the free list.
Definition: ssm-mem.c:48
The struct template of a heap-allocated closure object.
Definition: ssm.h:804
ssm_func_t f
Enter function pointer.
Definition: ssm.h:806
struct ssm_mm mm
Memory management header.
Definition: ssm.h:805
size_t pages_allocated
Number of pages allocated to this pool.
Definition: ssm-internal.h:252
size_t free_list_length
Length of the free list.
Definition: ssm-internal.h:253
size_t block_size
Size of this pool's blocks.
Definition: ssm-internal.h:251
Statistics for the heap; filled with ssm_mem_statistics_collect().
Definition: ssm-internal.h:263
size_t pages_allocated
Number of pages that have been allocated.
Definition: ssm-internal.h:266
size_t sizeof_ssm_mm
Size of per-object memory management header.
Definition: ssm-internal.h:264
ssm_mem_statistics_pool_t pool[32]
Size of the blocks in each pool.
Definition: ssm-internal.h:271
size_t live_objects
Number of live objects.
Definition: ssm-internal.h:269
size_t objects_allocated
Total number of allocated objects.
Definition: ssm-internal.h:267
size_t pool_count
Number of memory pools.
Definition: ssm-internal.h:270
size_t objects_freed
Total number of object free events.
Definition: ssm-internal.h:268
size_t page_size
Bytes in a memory page.
Definition: ssm-internal.h:265
The memory management metadata "header" for heap-allocated objects.
Definition: ssm.h:254
struct ssm_mm::@0::@1 variant
uint8_t tag
Which variant is inhabited by this object.
Definition: ssm.h:260
union ssm_mm::@0 info
Three "flavors" of information embedded in the header.
uint8_t ref_count
The number of references to this object.
Definition: ssm.h:255
uint8_t kind
The ssm_kind of object this is.
Definition: ssm.h:256
struct ssm_mm::@0::@2 vector
uint16_t size
16-bit size
Definition: ssm.h:266
A scheduled variable that supports scheduled updates with triggers.
Definition: ssm.h:588
ssm_time_t later_time
When the variable should be next updated.
Definition: ssm.h:590
ssm_time_t last_updated
When the variable was last updated.
Definition: ssm.h:591
ssm_value_t value
Current value.
Definition: ssm.h:593
ssm_trigger_t * triggers
List of sensitive continuations.
Definition: ssm.h:592
ssm_value_t later_value
Buffered value for delayed assignment.
Definition: ssm.h:594
struct ssm_mm mm
Definition: ssm.h:589
Heap-allocated time values.
Definition: ssm.h:408
ssm_time_t time
Time value payload.
Definition: ssm.h:410
struct ssm_mm mm
Embedded memory management header.
Definition: ssm.h:409
(The beginning of) a block of memory.
Definition: ssm-mem.c:28
union block * free_list_next
Pointer to the next block.
Definition: ssm-mem.c:29
uint8_t block_buf[1]
Variable-size buffer of the block.
Definition: ssm-mem.c:30
SSM values are either "packed" values or heap-allocated.
Definition: ssm.h:232
struct ssm_mm * heap_ptr
Pointer to a heap-allocated object.
Definition: ssm.h:233