ssm  0.0.2
Runtime Library for the Sparse Synchronous Model
Memory management

Values are always word-sized, and may point to heap-allocated, reference-counted objects; heap memory is allocated from a set of size-indexed memory pools. More...

Discussion

Values are always word-sized, and may point to heap-allocated, reference-counted objects; heap memory is allocated from a set of size-indexed memory pools.

For simplicity and flexibility, all values in SSM runtime are word-sized, represented using ssm_value_t. When the size of a value exceeds what can be represented by a word, the value is a pointer to a heap-allocated object. In particular, they point to a memory management metadata header, ssm_mm.

The SSM runtime uses reference counting to manage the lifetime of heap objects. The reference count is also maintained in the ssm_mm header. When a reference is duplicated, use ssm_dup() to increment its reference count. When a reference is dropped, use ssm_drop() decrement its reference and free if necessary. These macros first check whether the given ssm_value_t is heap-allocated before attempting to dereference the heap pointer; to skip this check (for example, if a value is known to be a heap object at compile time), use ssm_dup_unsafe() and ssm_drop_unsafe(). When the reference count of an object reaches zero, it is cleaned up and freed using ssm_drop_final(), which drop any references held by the soon-to-be-freed object.

The ssm_mm header's kind field indicates what ssm_kind the object is. This determines its memory layout in the heap, in particular where the object might hold references (pointers) to other heap objects. The interpretation and layout of the 16-bit info field depends on the kind, coming in three different "flavors": vector, variant, and size. All this information is used by ssm_drop_final() to figure out the number and location of values to ssm_drop(), as well as the size of the object to deallocate.

Heap objects are allocated for each ssm_kind using functions with prefix ssm_new_, such as ssm_new_adt() or ssm_new_time().

The SSM runtime comes with its own platform-agnostic allocator, parameterized by handlers set using ssm_mem_init(). It allocates small pieces of memory in blocks, within designated memory pools. Each memory pool consists of zero or more fixed-size memory pages, and are requested from the platform/OS on-demand via the alloc_page() handler. Meanwhile, allocations for larger ranges of memory are deferred to the alloc_mem() and free_mem() handlers.

The allocator's memory pools may be configured using the SSM_MEM_POOL_MIN, SSM_MEM_POOL_FACTOR_BASE2, SSM_MEM_POOL_COUNT, and SSM_MEM_PAGE_SIZE preprocessor constants. The default values produce 4 memory pools, of sizes 16B, 64B, 256B, and 1024B, and a memory page size of 4096B.

The runtime recognizes several compile time configuration macros that help with profiling and debugging. They are:

Data Structures

struct  ssm_mem_statistics_pool
 Statistics for a heap page pool; used in ssm_mem_statistics_t. More...
 
struct  ssm_mem_statistics
 Statistics for the heap; filled with ssm_mem_statistics_collect(). More...
 
union  ssm_value_t
 SSM values are either "packed" values or heap-allocated. More...
 
struct  ssm_mm
 The memory management metadata "header" for heap-allocated objects. More...
 

Macros

#define SSM_MEM_POOL_MIN   16
 Block size of the smallest memory pool. More...
 
#define SSM_MEM_POOL_FACTOR_BASE2   2
 Factor between each successive memory pool size, in base 2. More...
 
#define SSM_MEM_POOL_COUNT   4
 Number of memory pools. More...
 
#define SSM_MEM_POOL_SIZE(pool)    (SSM_MEM_POOL_MIN << (SSM_MEM_POOL_FACTOR_BASE2 * pool))
 Compute the size of a memory pool. More...
 
#define SSM_MEM_POOL_MAX   SSM_MEM_POOL_SIZE(SSM_MEM_POOL_COUNT - 1)
 The size of the largest memory pool. More...
 
#define SSM_MEM_PAGE_SIZE   SSM_MEM_POOL_SIZE(SSM_MEM_POOL_COUNT)
 The size of a memory page; must be greater than SSM_MEM_POOL_MAX. More...
 
#define ssm_marshal(v)    (ssm_value_t) { .packed_val = ((v) << 1 | 1) }
 Construct an ssm_value_t from a 31-bit integral value. More...
 
#define ssm_unmarshal(v)   ((v).packed_val >> 1)
 Extract an integral value from a packed ssm_value_t. More...
 
#define ssm_on_heap(v)   (((v).packed_val & 0x1) == 0)
 Whether a value is on the heap (i.e., is an object). More...
 
#define ssm_is_shared(v)   !(ssm_on_heap(v) && ((v).heap_ptr->ref_count == 1))
 Whether a value is shared, i.e., unsafe to modify. More...
 
#define ssm_dup(v)   (ssm_on_heap(v) ? ssm_dup_unsafe(v) : (v))
 Duplicate a possible heap reference, incrementing its ref count. More...
 
#define ssm_drop(v)
 Drop a reference to a possible heap item, and free it if necessary. More...
 
#define ssm_dup_unsafe(v)   ((++(v).heap_ptr->ref_count, (v)))
 Duplicate a heap reference, incrementing its ref count. More...
 
#define ssm_drop_unsafe(v)
 Drop a reference to a heap item, and free it if necessary. More...
 

Typedefs

typedef struct ssm_mem_statistics_pool ssm_mem_statistics_pool_t
 Statistics for a heap page pool; used in ssm_mem_statistics_t. More...
 
typedef struct ssm_mem_statistics ssm_mem_statistics_t
 Statistics for the heap; filled with ssm_mem_statistics_collect(). More...
 
typedef uint32_t ssm_word_t
 Values are 32-bits, the largest supported machine word size. More...
 

Enumerations

enum  ssm_kind {
  SSM_TIME_K = 0 , SSM_ADT_K , SSM_SV_K , SSM_CLOSURE_K ,
  SSM_ARRAY_K , SSM_BLOB_K
}
 The different kinds of heap objects, enumerated. More...
 

Functions

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. More...
 
void ssm_mem_destroy (void(*free_page_handler)(void *))
 Tears down the underlying allocator system. More...
 
void ssm_mem_statistics_collect (ssm_mem_statistics_t *stats)
 Collect and return statistics about the heap. More...
 
void ssm_drop_final (ssm_value_t v)
 Finalize and free a heap object. More...
 
void ssm_dups (size_t cnt, ssm_value_t *arr)
 Call ssm_dup() on an array of values. More...
 
void ssm_drops (size_t cnt, ssm_value_t *arr)
 Call ssm_drop() on an array of values. More...
 
void * ssm_mem_alloc (size_t size)
 Allocate a contiguous range of memory. More...
 
void ssm_mem_prealloc (size_t size, size_t num_pages)
 Preallocate memory pages to ensure capacity in memory pools. More...
 
void ssm_mem_free (void *m, size_t size)
 Deallocate memory allocated by ssm_mem_alloc(). More...
 

Macro Definition Documentation

◆ SSM_MEM_POOL_MIN

#define SSM_MEM_POOL_MIN   16

Block size of the smallest memory pool.

Must be strictly greater than the word size, i.e., the size of ssm_word_t.

Note
Intended for platform code; should not be used in user code.

Definition at line 185 of file ssm-internal.h.

◆ SSM_MEM_POOL_FACTOR_BASE2

#define SSM_MEM_POOL_FACTOR_BASE2   2

Factor between each successive memory pool size, in base 2.

Must be strictly greater than 0.

Note
Intended for platform code; should not be used in user code.

Definition at line 199 of file ssm-internal.h.

◆ SSM_MEM_POOL_COUNT

#define SSM_MEM_POOL_COUNT   4

Number of memory pools.

Must be strictly greater than 0.

Note
Intended for platform code; should not be used in user code.

Definition at line 213 of file ssm-internal.h.

◆ SSM_MEM_POOL_SIZE

#define SSM_MEM_POOL_SIZE (   pool)     (SSM_MEM_POOL_MIN << (SSM_MEM_POOL_FACTOR_BASE2 * pool))

Compute the size of a memory pool.

Note
Intended for platform code; should not be used in user code.
Parameters
poolthe 0-index of the memory pool.
Returns
the size of the memory pool at position pool.

Definition at line 227 of file ssm-internal.h.

◆ SSM_MEM_POOL_MAX

#define SSM_MEM_POOL_MAX   SSM_MEM_POOL_SIZE(SSM_MEM_POOL_COUNT - 1)

The size of the largest memory pool.

Note
Intended for platform code; should not be used in user code.

Definition at line 234 of file ssm-internal.h.

◆ SSM_MEM_PAGE_SIZE

#define SSM_MEM_PAGE_SIZE   SSM_MEM_POOL_SIZE(SSM_MEM_POOL_COUNT)

The size of a memory page; must be greater than SSM_MEM_POOL_MAX.

Note
Intended for platform code; should not be used in user code.

Definition at line 241 of file ssm-internal.h.

◆ ssm_marshal

#define ssm_marshal (   v)     (ssm_value_t) { .packed_val = ((v) << 1 | 1) }

Construct an ssm_value_t from a 31-bit integral value.

Parameters
vthe 31-bit integral value.
Returns
a packed ssm_value_t.

Definition at line 291 of file ssm.h.

◆ ssm_unmarshal

#define ssm_unmarshal (   v)    ((v).packed_val >> 1)

Extract an integral value from a packed ssm_value_t.

Parameters
vthe packed ssm_value_t.
Returns
the raw 31-bit integral value.

Definition at line 299 of file ssm.h.

◆ ssm_on_heap

#define ssm_on_heap (   v)    (((v).packed_val & 0x1) == 0)

Whether a value is on the heap (i.e., is an object).

Parameters
vpointer to the ssm_value_t.
Returns
non-zero if on heap, zero otherwise.

Definition at line 306 of file ssm.h.

◆ ssm_is_shared

#define ssm_is_shared (   v)    !(ssm_on_heap(v) && ((v).heap_ptr->ref_count == 1))

Whether a value is shared, i.e., unsafe to modify.

The opposite of "shared" is "unique," as in C++'s "unique_ptr."

Parameters
vpointer to the ssm_value_t.
Returns
non-zero if shared, zero otherwise.

Definition at line 315 of file ssm.h.

◆ ssm_dup

#define ssm_dup (   v)    (ssm_on_heap(v) ? ssm_dup_unsafe(v) : (v))

Duplicate a possible heap reference, incrementing its ref count.

If the caller knows v is definitely on the heap, call ssm_drop_unsafe() to eliminate the heap check (and omit call if it is definitely not on the heap).

Parameters
vpointer to the ssm_mm header of the heap item.

Definition at line 325 of file ssm.h.

◆ ssm_drop

#define ssm_drop (   v)
Value:
do \
if (ssm_on_heap(v)) \
ssm_drop_unsafe(v); \
while (0)
#define ssm_on_heap(v)
Whether a value is on the heap (i.e., is an object).
Definition: ssm.h:306

Drop a reference to a possible heap item, and free it if necessary.

If v is freed, all references held by the heap item itself will also be be dropped.

If the caller knows that v is definitely a heap item, call ssm_drop_unsafe() to eliminate the heap check (and omit call if it is definitely not on the heap).

Parameters
vssm_value_t to be dropped.

Definition at line 338 of file ssm.h.

◆ ssm_dup_unsafe

#define ssm_dup_unsafe (   v)    ((++(v).heap_ptr->ref_count, (v)))

Duplicate a heap reference, incrementing its ref count.

Called by ssm_dup().

Note
assumes that v is a heap pointer, i.e., ssm_on_heap(v).
Parameters
vpointer to the ssm_mm header of the heap item.

Definition at line 352 of file ssm.h.

◆ ssm_drop_unsafe

#define ssm_drop_unsafe (   v)
Value:
do \
if (--(v).heap_ptr->ref_count == 0) \
ssm_drop_final(v); \
while (0)

Drop a reference to a heap item, and free it if necessary.

If v is freed, ssm_drop_final() will be called to drop all heap objects v refers to.

Called by ssm_drop().

Note
assumes that v is a heap pointer, i.e., ssm_on_heap(v).
Parameters
vssm_value_t to be dropped.
Returns
0 on success.

Definition at line 366 of file ssm.h.

Typedef Documentation

◆ ssm_mem_statistics_pool_t

Statistics for a heap page pool; used in ssm_mem_statistics_t.

Note
Define CONFIG_MEM_STATS to enable this.

◆ ssm_mem_statistics_t

Statistics for the heap; filled with ssm_mem_statistics_collect().

A collection of satistics collected by ssm_mem_statistics_collect() and designed to be printed by a function you supply.

Note
Define CONFIG_MEM_STATS to enable this.

◆ ssm_word_t

typedef uint32_t ssm_word_t

Values are 32-bits, the largest supported machine word size.

Definition at line 229 of file ssm.h.

Enumeration Type Documentation

◆ ssm_kind

enum ssm_kind

The different kinds of heap objects, enumerated.

Types enumerated here that are not ADTs are chosen because they cannot be easily or efficiently expressed as a product of words. For instance, 64-bit timestamps cannot be directly stored in the payload of a regular heap object, where even-numbered timestamps may be misinterpreted as pointers.

Enumerator
SSM_TIME_K 

64-bit timestamps, ssm_time_t

SSM_ADT_K 

ADT object, e.g., ssm_adt1.

SSM_SV_K 

Scheduled variables, ssm_sv_t.

SSM_CLOSURE_K 

Closure object, e.g., ssm_closure1.

SSM_ARRAY_K 

Array of values, e.g., ssm_array1.

SSM_BLOB_K 

Blob of arbitrary data, e.g., ssm_blob1.

Definition at line 277 of file ssm.h.

Function Documentation

◆ ssm_mem_init()

void ssm_mem_init ( void *(*)(void)  alloc_page_handler,
void *(*)(size_t)  alloc_mem_handler,
void(*)(void *, size_t)  free_mem_handler 
)

Initializes the underlying allocator system.

Memory pages are requested from the platform/OS on-demand via the provided alloc_page_handler. This handler must return a pointer to the beginning of a range of memory of size SSM_MEM_PAGE_SIZE, and the page must be zeroed out. These pages are assumed to never be freed.

To support arbitrarily large allocations, SSM's allocator uses alloc_mem_handler to allocate memory, and free_mem_handler to release it. There are no requirements on the contents of memory allocated with alloc_mem_handler. These handlers may also assume they will not be invoked to request memory ranges of less than SSM_MEM_POOL_MAX bytes.

If the allocator is compiled with valgrind support (i.e., USE_VALGRIND is defined), it will perform a leak-check summary, to checkpoint how much memory has already been allocated.

Note
Intended for platform code; should not be used in user code.
Parameters
alloc_page_handlerallocates pages.
alloc_mem_handlerallocates arbitrarily large.
free_mem_handlerfrees memory allocated with alloc_mem_handler.

Definition at line 136 of file ssm-mem.c.

◆ ssm_mem_destroy()

void ssm_mem_destroy ( void(*)(void *)  free_page_handler)

Tears down the underlying allocator system.

If the allocator is compiled with valgrind support (i.e., USE_VALGRIND is defined), it will perform a full leak-check summary, to report how much memory has been leaked since ssm_mem_init().

Todo:
this doesn't actually call free_page_handler yet. It still needs to be implemented, perhaps with the help of a superblock header to keep track of all pages allocated for each mempool
Note
Intended for platform code; should not be used in user code.
Parameters
free_page_handlerfrees pages allocated with alloc_page_handler.

Definition at line 156 of file ssm-mem.c.

◆ ssm_mem_statistics_collect()

void ssm_mem_statistics_collect ( ssm_mem_statistics_t stats)

Collect and return statistics about the heap.

Note
Define CONFIG_MEM_STATS to enable this.
Parameters
statsnon-NULL pointer to a ssm_mem_statistics_t to be filled in

Definition at line 378 of file ssm-mem.c.

◆ ssm_drop_final()

void ssm_drop_final ( ssm_value_t  v)

Finalize and free a heap object.

Drops all heap objects v refers to, and perform any additional finalization as required by the ssm_kind of v.

Called by ssm_drop_unsafe().

Note
assumes that v is a heap pointer, i.e., ssm_on_heap(v).
Parameters
vssm_value_t to be finalized and freed.

Definition at line 325 of file ssm-mem.c.

◆ ssm_dups()

void ssm_dups ( size_t  cnt,
ssm_value_t arr 
)

Call ssm_dup() on an array of values.

Definition at line 367 of file ssm-mem.c.

◆ ssm_drops()

void ssm_drops ( size_t  cnt,
ssm_value_t arr 
)

Call ssm_drop() on an array of values.

Definition at line 372 of file ssm-mem.c.

◆ ssm_mem_alloc()

void* ssm_mem_alloc ( size_t  size)

Allocate a contiguous range of memory.

Memory will be allocated from an appropriately sized memory pool, if one is available. Guaranteed to be aligned against the smallest power of 2 greater than size.

Parameters
sizethe requested memory range size, in bytes.
Returns
pointer to the first byte of the allocate memory block.

Definition at line 183 of file ssm-mem.c.

◆ ssm_mem_prealloc()

void ssm_mem_prealloc ( size_t  size,
size_t  num_pages 
)

Preallocate memory pages to ensure capacity in memory pools.

Does nothing if no memory pool will fit a block of size.

Parameters
sizesize whose memory pool should be preallocaed pages.
num_pagesnumber of pages to allocate.

◆ ssm_mem_free()

void ssm_mem_free ( void *  m,
size_t  size 
)

Deallocate memory allocated by ssm_mem_alloc().

The behavior of freeing memory not allocated by ssm_mem_alloc() is undefined.

Parameters
mpointer to the memory range allocated by ssm_mem_alloc().
sizethe size of the memory range allocated by ssm_mem_alloc().

Definition at line 233 of file ssm-mem.c.