RTE OSAdapter POSIX 0.1.0 build 41b3eb3
POSIX/Linux OAL OSAdapter for Platform_RTE
Loading...
Searching...
No Matches
rte_posix_osadapter_memory.c
Go to the documentation of this file.
1/* _POSIX_C_SOURCE: glibc declares PTHREAD_PRIO_INHERIT and pthread_mutexattr_setprotocol() only under a POSIX
2 * feature-test macro (this product builds strict C99), same as mutex.c's own; rte_posix_osadapter_lock.h needs it
3 * too. */
4#define _POSIX_C_SOURCE 200809L
5
55#include "rte/utils/cast/rte_cast.h"
58
59#include <pthread.h>
60#include <stdint.h>
61#include "rte/oal/memory/rte_mem_util.h"
62
64#ifndef RTE_POSIX_MEM_ARENA_SIZE
65#define RTE_POSIX_MEM_ARENA_SIZE (1024U * 1024U)
66#endif
67/* Longest wait for g_mem_lock, in ms (OSA rule R2, REQ-OAL-MEM-015). Far above a critical section's hold time (a
68 * handful of pointer/counter updates), well below the A/B checkpoint budget (400 ms); 0 makes every pool operation one
69 * non-blocking try. */
70#ifndef RTE_POSIX_MEM_LOCK_TIMEOUT_MS
71#define RTE_POSIX_MEM_LOCK_TIMEOUT_MS 50U
72#endif
73
75typedef struct
76{
77 uint8_t *base;
78 size_t block_size;
79 size_t block_count;
80 size_t free_count;
81 void *free_list_head;
83
84/* C99-compatible static assert: posix_mem_pool_state_t must fit inside
85 * rte_mem_pool_storage_t's reserved bytes. */
86typedef char posix_mem_pool_storage_fits_[(sizeof(posix_mem_pool_state_t) <= sizeof(rte_mem_pool_storage_t)) ? 1
87 : -1];
88
90static rte_status_t osadapter_create(rte_mem_pool_storage_t *storage, const rte_mem_pool_config_t *config,
91 rte_mem_pool_handle_t *out_handle);
92static rte_status_t osadapter_acquire(rte_mem_pool_handle_t handle, void **out_block);
93static bool block_belongs_to_pool(const posix_mem_pool_state_t *state, const void *block);
94static rte_status_t osadapter_release(rte_mem_pool_handle_t handle, void *block);
95static rte_status_t osadapter_stats(rte_mem_pool_handle_t handle, size_t *out_free_blocks, size_t *out_used_blocks);
96static rte_status_t mem_lock(void);
97
100static size_t g_arena_used = 0U;
101static pthread_mutex_t g_mem_lock; /* created by rte_posix_osadapter_memory_init(), see file header */
102static bool g_mem_initialised = false; /* true once g_mem_lock exists */
103static const rte_osadapter_memory_t s_posix_memory_osadapter = { osadapter_create, osadapter_acquire, osadapter_release,
104 osadapter_stats };
105
107
108
110const rte_osadapter_memory_t *rte_posix_osadapter_memory(void)
111{
112 return &s_posix_memory_osadapter;
113}
114
116{
117 rte_status_t status = RTE_STATUS_OK;
118 pthread_mutexattr_t attr;
119
120 if (!g_mem_initialised)
121 {
122 /* OSA rule R2 (REQ-OAL-MUTEX-004): the pool lock uses priority inheritance, requested at run time on every
123 * host exactly as mutex.c's create does (no _POSIX_THREAD_PRIO_INHERIT compile gate). A refusal at any of
124 * the three calls fails the init; there is no fallback to a plain mutex. */
125 if (pthread_mutexattr_init(&attr) != 0)
126 {
127 status = RTE_STATUS_INTERNAL_ERROR;
128 }
129 else
130 {
131 if (pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT) != 0)
132 {
133 status = RTE_STATUS_INTERNAL_ERROR;
134 }
135 else if (pthread_mutex_init(&g_mem_lock, &attr) != 0)
136 {
137 status = RTE_STATUS_INTERNAL_ERROR;
138 }
139 else
140 {
141 /* priority-inheritance pool lock initialised */
142 }
143 (void)pthread_mutexattr_destroy(&attr);
144 }
145
146 if (status == RTE_STATUS_OK)
147 {
148 g_mem_initialised = true;
149 }
150 else
151 {
152 /* OSA rule R6: report the violation; the pool stays uninitialised and the caller's setup fails. */
153 POSIX_OSA_REPORT_RT_ATTRIBUTE("memory pool lock refused priority inheritance - init failed");
154 }
155 }
156
157 return status;
158}
159
160
161/****Local functions ****/
162
163static rte_status_t osadapter_create(rte_mem_pool_storage_t *storage, const rte_mem_pool_config_t *config,
164 rte_mem_pool_handle_t *out_handle)
165{
167 rte_status_t status;
168 size_t total_bytes;
169 size_t i;
170 uint8_t *base;
171
172 if ((storage == NULL) || (config == NULL) || (out_handle == NULL) || (config->block_size == 0U)
173 || (config->block_count == 0U))
174 {
175 return RTE_STATUS_INVALID_PARAM;
176 }
177 if (config->block_size < sizeof(void *))
178 {
179 return RTE_STATUS_INVALID_PARAM; /* too small for the intrusive free list, see file header */
180 }
181
182 /* Overflow-checked multiply (safeAPIFreamwork REQ-COMMON-CAST-004) -
183 * replaces this file's own former hand-rolled "divide back and
184 * compare" idiom with the framework's shared primitive. */
185 if (rte_cast_checked_mul_size(config->block_size, config->block_count, &total_bytes) != RTE_STATUS_OK)
186 {
187 return RTE_STATUS_INVALID_PARAM; /* block_size * block_count overflowed size_t */
188 }
189 status = mem_lock();
190 if (status != RTE_STATUS_OK)
191 {
192 return status;
193 }
194 if (total_bytes > (RTE_POSIX_MEM_ARENA_SIZE - g_arena_used))
195 {
196 (void)pthread_mutex_unlock(&g_mem_lock);
197 return RTE_STATUS_RESOURCE_EXHAUSTED;
198 }
199
200 base = &g_arena[g_arena_used];
201 g_arena_used += total_bytes;
202 (void)pthread_mutex_unlock(&g_mem_lock); /* the claimed range is private to this pool from here on */
203
204 for (i = 0U; i < config->block_count; i++)
205 {
206 uint8_t *block = base + (i * config->block_size);
207 void *next = (i + 1U < config->block_count) ? (void *)(base + ((i + 1U) * config->block_size)) : NULL;
208
209 rte_mem_copy(block, &next, sizeof(next));
210 }
211
212 state = (posix_mem_pool_state_t *)(void *)storage;
213 state->base = base;
214 state->block_size = config->block_size;
215 state->block_count = config->block_count;
216 state->free_count = config->block_count;
217 state->free_list_head = (void *)base;
218
219 *out_handle = (rte_mem_pool_handle_t)(void *)storage;
220 return RTE_STATUS_OK;
221}
222
223static rte_status_t osadapter_acquire(rte_mem_pool_handle_t handle, void **out_block)
224{
225 posix_mem_pool_state_t *state = (posix_mem_pool_state_t *)(void *)handle;
226 rte_status_t status;
227 void *block;
228 void *next;
229
230 if ((state == NULL) || (out_block == NULL))
231 {
232 return RTE_STATUS_INVALID_PARAM;
233 }
234 status = mem_lock();
235 if (status != RTE_STATUS_OK)
236 {
237 *out_block = NULL;
238 return status;
239 }
240 if (state->free_list_head == NULL)
241 {
242 (void)pthread_mutex_unlock(&g_mem_lock);
243 *out_block = NULL;
244 return RTE_STATUS_RESOURCE_EXHAUSTED;
245 }
246
247 block = state->free_list_head;
248 rte_mem_copy(&next, block, sizeof(next));
249 state->free_list_head = next;
250 state->free_count -= 1U;
251 (void)pthread_mutex_unlock(&g_mem_lock);
252 *out_block = block;
253 return RTE_STATUS_OK;
254}
255
256static bool block_belongs_to_pool(const posix_mem_pool_state_t *state, const void *block)
257{
258 const uint8_t *b = (const uint8_t *)block;
259 size_t byte_offset;
260
261 if ((b < state->base) || (b >= (state->base + (state->block_size * state->block_count))))
262 {
263 return false;
264 }
265 byte_offset = (size_t)(b - state->base);
266 return (byte_offset % state->block_size) == 0U;
267}
268
269static rte_status_t osadapter_release(rte_mem_pool_handle_t handle, void *block)
270{
271 posix_mem_pool_state_t *state = (posix_mem_pool_state_t *)(void *)handle;
272 rte_status_t status;
273
274 if ((state == NULL) || (block == NULL))
275 {
276 return RTE_STATUS_INVALID_PARAM;
277 }
278 if (!g_mem_initialised)
279 {
280 return RTE_STATUS_INVALID_STATE; /* no pool exists before init; checked before the pool state is read */
281 }
282 if (!block_belongs_to_pool(state, block))
283 {
284 return RTE_STATUS_INVALID_PARAM;
285 }
286
287 status = mem_lock();
288 if (status != RTE_STATUS_OK)
289 {
290 return status;
291 }
292 rte_mem_copy(block, &state->free_list_head, sizeof(state->free_list_head));
293 state->free_list_head = block;
294 state->free_count += 1U;
295 (void)pthread_mutex_unlock(&g_mem_lock);
296 return RTE_STATUS_OK;
297}
298
299static rte_status_t osadapter_stats(rte_mem_pool_handle_t handle, size_t *out_free_blocks, size_t *out_used_blocks)
300{
301 posix_mem_pool_state_t *state = (posix_mem_pool_state_t *)(void *)handle;
302 rte_status_t status;
303
304 if ((state == NULL) || (out_free_blocks == NULL) || (out_used_blocks == NULL))
305 {
306 return RTE_STATUS_INVALID_PARAM;
307 }
308 status = mem_lock();
309 if (status != RTE_STATUS_OK)
310 {
311 return status;
312 }
313 *out_free_blocks = state->free_count;
314 *out_used_blocks = state->block_count - state->free_count;
315 (void)pthread_mutex_unlock(&g_mem_lock);
316 return RTE_STATUS_OK;
317}
318
319/* Takes the pool lock, waiting at most RTE_POSIX_MEM_LOCK_TIMEOUT_MS (OSA rule R2, REQ-OAL-MEM-015):
320 * RTE_STATUS_INVALID_STATE (lock not touched) until rte_posix_osadapter_memory_init() has succeeded; otherwise
321 * posix_osa_lock_bounded()'s result - RTE_STATUS_OK with the lock held, RTE_STATUS_TIMEOUT when it was not acquired
322 * within the bound, RTE_STATUS_INTERNAL_ERROR for a platform failure (lock not held in either case). */
323static rte_status_t mem_lock(void)
324{
325 rte_status_t status;
326
327 if (!g_mem_initialised)
328 {
329 status = RTE_STATUS_INVALID_STATE;
330 }
331 else
332 {
333 status = posix_osa_lock_bounded(&g_mem_lock, RTE_POSIX_MEM_LOCK_TIMEOUT_MS);
334 }
335
336 return status;
337}
Real POSIX/Linux OSAdapter for every OAL service (ADR-018).
const rte_osadapter_memory_t * rte_posix_osadapter_memory(void)
The POSIX rte_memory OSAdapter (static arena, no malloc). Its operations return RTE_STATUS_INVALID_ST...
rte_status_t rte_posix_osadapter_memory_init(void)
Creates the memory OSAdapter's pool lock as a priority-inheritance mutex (OSA rule R2,...
static rte_status_t osadapter_create(rte_ipc_storage_t *storage, const rte_ipc_config_t *config, rte_ipc_handle_t *out_handle)
rte_status_t posix_osa_lock_bounded(pthread_mutex_t *mutex, rte_duration_ms_t timeout_ms)
Waits at most timeout_ms for a pthread mutex.
Private helper: a bounded wait for a pthread mutex (OSA rule R2: every wait bounded).
#define RTE_POSIX_MEM_ARENA_SIZE
static uint8_t g_arena[RTE_POSIX_MEM_ARENA_SIZE]
Private helper: reports a real-time attribute this OSAdapter could not apply (OSA rules R1/R2/R6).