SafeAPI Backend POSIX
POSIX/Linux OAL backend for safeAPIFreamwork
Loading...
Searching...
No Matches
sapi_posix_backend_memory.c
Go to the documentation of this file.
1
34#include "safeapi/utils/cast/sapi_cast.h"
35
36#include <stdint.h>
37#include "safeapi/oal/memory/sapi_mem_util.h"
38
40#ifndef SAPI_POSIX_MEM_ARENA_SIZE
41#define SAPI_POSIX_MEM_ARENA_SIZE (1024U * 1024U)
42#endif
43
45typedef struct
46{
47 uint8_t *base;
48 size_t block_size;
49 size_t block_count;
50 size_t free_count;
51 void *free_list_head;
53
54/* C99-compatible static assert: posix_mem_pool_state_t must fit inside
55 * sapi_mem_pool_storage_t's reserved bytes. */
56typedef char posix_mem_pool_storage_fits_[(sizeof(posix_mem_pool_state_t) <= sizeof(sapi_mem_pool_storage_t)) ? 1
57 : -1];
58
60static sapi_status_t backend_create(sapi_mem_pool_storage_t *storage, const sapi_mem_pool_config_t *config,
61 sapi_mem_pool_handle_t *out_handle);
62static sapi_status_t backend_acquire(sapi_mem_pool_handle_t handle, void **out_block);
63static bool block_belongs_to_pool(const posix_mem_pool_state_t *state, const void *block);
64static sapi_status_t backend_release(sapi_mem_pool_handle_t handle, void *block);
65static sapi_status_t backend_stats(sapi_mem_pool_handle_t handle, size_t *out_free_blocks, size_t *out_used_blocks);
66
69static size_t g_arena_used = 0U;
70static const sapi_mem_pool_backend_t s_posix_memory_backend = { backend_create, backend_acquire, backend_release,
71 backend_stats };
72
74
75
77const sapi_mem_pool_backend_t *sapi_posix_backend_memory(void)
78{
79 return &s_posix_memory_backend;
80}
81
82
83/****Local functions ****/
84
85static sapi_status_t backend_create(sapi_mem_pool_storage_t *storage, const sapi_mem_pool_config_t *config,
86 sapi_mem_pool_handle_t *out_handle)
87{
89 size_t total_bytes;
90 size_t i;
91 uint8_t *base;
92
93 if ((storage == NULL) || (config == NULL) || (out_handle == NULL) || (config->block_size == 0U)
94 || (config->block_count == 0U))
95 {
96 return SAPI_STATUS_INVALID_PARAM;
97 }
98 if (config->block_size < sizeof(void *))
99 {
100 return SAPI_STATUS_INVALID_PARAM; /* too small for the intrusive free list, see file header */
101 }
102
103 /* Overflow-checked multiply (safeAPIFreamwork REQ-COMMON-CAST-004) -
104 * replaces this file's own former hand-rolled "divide back and
105 * compare" idiom with the framework's shared primitive. */
106 if (sapi_cast_checked_mul_size(config->block_size, config->block_count, &total_bytes) != SAPI_STATUS_OK)
107 {
108 return SAPI_STATUS_INVALID_PARAM; /* block_size * block_count overflowed size_t */
109 }
110 if (total_bytes > (SAPI_POSIX_MEM_ARENA_SIZE - g_arena_used))
111 {
112 return SAPI_STATUS_RESOURCE_EXHAUSTED;
113 }
114
115 base = &g_arena[g_arena_used];
116 g_arena_used += total_bytes;
117
118 for (i = 0U; i < config->block_count; i++)
119 {
120 uint8_t *block = base + (i * config->block_size);
121 void *next = (i + 1U < config->block_count) ? (void *)(base + ((i + 1U) * config->block_size)) : NULL;
122
123 sapi_mem_copy(block, &next, sizeof(next));
124 }
125
126 state = (posix_mem_pool_state_t *)(void *)storage;
127 state->base = base;
128 state->block_size = config->block_size;
129 state->block_count = config->block_count;
130 state->free_count = config->block_count;
131 state->free_list_head = (void *)base;
132
133 *out_handle = (sapi_mem_pool_handle_t)(void *)storage;
134 return SAPI_STATUS_OK;
135}
136
137static sapi_status_t backend_acquire(sapi_mem_pool_handle_t handle, void **out_block)
138{
139 posix_mem_pool_state_t *state = (posix_mem_pool_state_t *)(void *)handle;
140 void *block;
141 void *next;
142
143 if ((state == NULL) || (out_block == NULL))
144 {
145 return SAPI_STATUS_INVALID_PARAM;
146 }
147 if (state->free_list_head == NULL)
148 {
149 *out_block = NULL;
150 return SAPI_STATUS_RESOURCE_EXHAUSTED;
151 }
152
153 block = state->free_list_head;
154 sapi_mem_copy(&next, block, sizeof(next));
155 state->free_list_head = next;
156 state->free_count -= 1U;
157 *out_block = block;
158 return SAPI_STATUS_OK;
159}
160
161static bool block_belongs_to_pool(const posix_mem_pool_state_t *state, const void *block)
162{
163 const uint8_t *b = (const uint8_t *)block;
164 size_t byte_offset;
165
166 if ((b < state->base) || (b >= (state->base + (state->block_size * state->block_count))))
167 {
168 return false;
169 }
170 byte_offset = (size_t)(b - state->base);
171 return (byte_offset % state->block_size) == 0U;
172}
173
174static sapi_status_t backend_release(sapi_mem_pool_handle_t handle, void *block)
175{
176 posix_mem_pool_state_t *state = (posix_mem_pool_state_t *)(void *)handle;
177
178 if ((state == NULL) || (block == NULL))
179 {
180 return SAPI_STATUS_INVALID_PARAM;
181 }
182 if (!block_belongs_to_pool(state, block))
183 {
184 return SAPI_STATUS_INVALID_PARAM;
185 }
186
187 sapi_mem_copy(block, &state->free_list_head, sizeof(state->free_list_head));
188 state->free_list_head = block;
189 state->free_count += 1U;
190 return SAPI_STATUS_OK;
191}
192
193static sapi_status_t backend_stats(sapi_mem_pool_handle_t handle, size_t *out_free_blocks, size_t *out_used_blocks)
194{
195 posix_mem_pool_state_t *state = (posix_mem_pool_state_t *)(void *)handle;
196
197 if ((state == NULL) || (out_free_blocks == NULL) || (out_used_blocks == NULL))
198 {
199 return SAPI_STATUS_INVALID_PARAM;
200 }
201 *out_free_blocks = state->free_count;
202 *out_used_blocks = state->block_count - state->free_count;
203 return SAPI_STATUS_OK;
204}
Real POSIX/Linux backend for every OAL service (ADR-018).
const sapi_mem_pool_backend_t * sapi_posix_backend_memory(void)
The POSIX sapi_memory backend (static arena, no malloc).
#define SAPI_POSIX_MEM_ARENA_SIZE
static uint8_t g_arena[SAPI_POSIX_MEM_ARENA_SIZE]