QP/C  7.0.0
Real-Time Embedded Framework
qf_mem.c
Go to the documentation of this file.
1/*============================================================================
2* QP/C Real-Time Embedded Framework (RTEF)
3* Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
4*
5* SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
6*
7* This software is dual-licensed under the terms of the open source GNU
8* General Public License version 3 (or any later version), or alternatively,
9* under the terms of one of the closed source Quantum Leaps commercial
10* licenses.
11*
12* The terms of the open source GNU General Public License version 3
13* can be found at: <www.gnu.org/licenses/gpl-3.0>
14*
15* The terms of the closed source Quantum Leaps commercial licenses
16* can be found at: <www.state-machine.com/licensing>
17*
18* Redistributions in source code must retain this top-level comment block.
19* Plagiarizing this software to sidestep the license obligations is illegal.
20*
21* Contact information:
22* <www.state-machine.com>
23* <info@state-machine.com>
24============================================================================*/
32#define QP_IMPL /* this is QP implementation */
33#include "qf_port.h" /* QF port */
34#include "qf_pkg.h" /* QF package-scope interface */
35#include "qassert.h" /* QP embedded systems-friendly assertions */
36#ifdef Q_SPY /* QS software tracing enabled? */
37 #include "qs_port.h" /* QS port */
38 #include "qs_pkg.h" /* QS facilities for pre-defined trace records */
39#else
40 #include "qs_dummy.h" /* disable the QS software tracing */
41#endif /* Q_SPY */
42
44
45/*==========================================================================*/
82void QMPool_init(QMPool * const me, void * const poolSto,
83 uint_fast32_t poolSize, uint_fast16_t blockSize)
84{
89 Q_REQUIRE_ID(100, (poolSto != (void *)0)
90 && (poolSize >= (uint_fast32_t)sizeof(QFreeBlock))
91 && ((uint_fast16_t)(blockSize + sizeof(QFreeBlock)) > blockSize));
92
93 me->free_head = poolSto;
94
95 /* round up the blockSize to fit an integer # free blocks, no division */
96 me->blockSize = (QMPoolSize)sizeof(QFreeBlock); /* start with just one */
97
98 /* #free blocks that fit in one memory block */
99 uint_fast16_t nblocks = 1U;
100 while (me->blockSize < (QMPoolSize)blockSize) {
101 me->blockSize += (QMPoolSize)sizeof(QFreeBlock);
102 ++nblocks;
103 }
104 blockSize = (uint_fast16_t)me->blockSize; /* round-up to nearest block */
105
106 /* the pool buffer must fit at least one rounded-up block */
107 Q_ASSERT_ID(110, poolSize >= blockSize);
108
109 /* chain all blocks together in a free-list... */
110 poolSize -= (uint_fast32_t)blockSize; /* don't count the last block */
111 me->nTot = 1U; /* the last block already in the pool */
112
113 /* start at the head of the free list */
114 QFreeBlock *fb = (QFreeBlock *)me->free_head;
115
116 /* chain all blocks together in a free-list... */
117 while (poolSize >= (uint_fast32_t)blockSize) {
118 fb->next = &QF_PTR_AT_(fb, nblocks);/*point next link to next block */
119 fb = fb->next; /* advance to the next block */
120 poolSize -= (uint_fast32_t)blockSize; /* reduce available pool size */
121 ++me->nTot; /* increment the number of blocks so far */
122 }
123
124 fb->next = (QFreeBlock *)0; /* the last link points to NULL */
125 me->nFree = me->nTot; /* all blocks are free */
126 me->nMin = me->nTot; /* the minimum number of free blocks */
127 me->start = poolSto; /* the original start this pool buffer */
128 me->end = fb; /* the last block in this pool */
129}
130
131/*==========================================================================*/
154void QMPool_put(QMPool * const me, void *b, uint_fast8_t const qs_id) {
155 (void)qs_id; /* unused parameter (outside Q_SPY build configuration) */
156
160 Q_REQUIRE_ID(200, (me->nFree < me->nTot)
161 && QF_PTR_RANGE_(b, me->start, me->end));
162
164 QF_CRIT_E_();
165 ((QFreeBlock *)b)->next = (QFreeBlock *)me->free_head;/* link into list */
166 me->free_head = b; /* set as new head of the free list */
167 ++me->nFree; /* one more free block in this pool */
168
170 QS_TIME_PRE_(); /* timestamp */
171 QS_OBJ_PRE_(me); /* this memory pool */
172 QS_MPC_PRE_(me->nFree); /* the number of free blocks in the pool */
174
175 QF_CRIT_X_();
176}
177
178/*==========================================================================*/
212void *QMPool_get(QMPool * const me, uint_fast16_t const margin,
213 uint_fast8_t const qs_id)
214{
215 (void)qs_id; /* unused parameter, if Q_SPY not defined */
216
218 QF_CRIT_E_();
219
220 /* have more free blocks than the requested margin? */
221 QFreeBlock *fb;
222 if (me->nFree > (QMPoolCtr)margin) {
223 void *fb_next;
224 fb = (QFreeBlock *)me->free_head; /* get a free block */
225
226 /* the pool has some free blocks, so a free block must be available */
227 Q_ASSERT_CRIT_(310, fb != (QFreeBlock *)0);
228
229 fb_next = fb->next; /* put volatile to a temporary to avoid UB */
230
231 /* is the pool becoming empty? */
232 --me->nFree; /* one less free block */
233 if (me->nFree == 0U) {
234 /* pool is becoming empty, so the next free block must be NULL */
235 Q_ASSERT_CRIT_(320, fb_next == (QFreeBlock *)0);
236
237 me->nMin = 0U; /* remember that the pool got empty */
238 }
239 else {
240 /* pool is not empty, so the next free block must be in range
241 *
242 * NOTE: the next free block pointer can fall out of range
243 * when the client code writes past the memory block, thus
244 * corrupting the next block.
245 */
246 Q_ASSERT_CRIT_(330, QF_PTR_RANGE_(fb_next, me->start, me->end));
247
248 /* is the number of free blocks the new minimum so far? */
249 if (me->nMin > me->nFree) {
250 me->nMin = me->nFree; /* remember the new minimum */
251 }
252 }
253
254 me->free_head = fb_next; /* set the head to the next free block */
255
257 QS_TIME_PRE_(); /* timestamp */
258 QS_OBJ_PRE_(me); /* this memory pool */
259 QS_MPC_PRE_(me->nFree); /* # of free blocks in the pool */
260 QS_MPC_PRE_(me->nMin); /* min # free blocks ever in the pool */
262 }
263 /* don't have enough free blocks at this point */
264 else {
265 fb = (QFreeBlock *)0;
266
268 QS_TIME_PRE_(); /* timestamp */
269 QS_OBJ_PRE_(me); /* this memory pool */
270 QS_MPC_PRE_(me->nFree); /* # of free blocks in the pool */
271 QS_MPC_PRE_(margin); /* the requested margin */
273 }
274 QF_CRIT_X_();
275
276 return fb; /* return the block or NULL pointer to the caller */
277}
278
279/*==========================================================================*/
293uint_fast16_t QF_getPoolMin(uint_fast8_t const poolId) {
294
296 Q_REQUIRE_ID(400, (poolId <= QF_MAX_EPOOL)
297 && (0U < poolId) && (poolId <= QF_maxPool_));
298
300 QF_CRIT_E_();
301 uint_fast16_t const min = (uint_fast16_t)QF_pool_[poolId - 1U].nMin;
302 QF_CRIT_X_();
303
304 return min;
305}
Customizable and memory-efficient assertions for embedded systems.
#define Q_DEFINE_THIS_MODULE(name_)
Definition: qassert.h:102
#define Q_ASSERT_ID(id_, test_)
Definition: qassert.h:135
#define Q_REQUIRE_ID(id_, test_)
Definition: qassert.h:252
uint_fast8_t QF_maxPool_
Definition: qf_dyn.c:48
QF_EPOOL_TYPE_ QF_pool_[QF_MAX_EPOOL]
Definition: qf_dyn.c:47
Internal (package scope) QF/C interface.
#define QF_CRIT_STAT_
Definition: qf_pkg.h:54
#define QF_PTR_AT_(base_, i_)
Definition: qf_pkg.h:183
struct QFreeBlock *volatile next
Definition: qf_pkg.h:168
#define Q_ASSERT_CRIT_(id_, test_)
Definition: qf_pkg.h:97
#define QF_CRIT_X_()
Definition: qf_pkg.h:78
#define QF_PTR_RANGE_(x_, min_, max_)
Definition: qf_pkg.h:193
#define QF_CRIT_E_()
Definition: qf_pkg.h:66
uint8_t QMPoolSize
Definition: qmpool.h:50
uint8_t QMPoolCtr
Definition: qmpool.h:75
#define QS_TIME_PRE_()
Definition: qs.h:220
@ QS_QF_MPOOL_GET_ATTEMPT
Definition: qs.h:124
@ QS_QF_MPOOL_PUT
Definition: qs.h:90
@ QS_QF_MPOOL_GET
Definition: qs.h:89
Internal (package scope) QS/C interface.
#define QS_BEGIN_NOCRIT_PRE_(rec_, qs_id_)
Definition: qs_pkg.h:138
#define QS_OBJ_PRE_(obj_)
Definition: qs_pkg.h:179
#define QS_MPC_PRE_(ctr_)
Definition: qs_pkg.h:249
#define QS_END_NOCRIT_PRE_()
Definition: qs_pkg.h:148
Definition: qmpool.h:105
void QMPool_init(QMPool *const me, void *const poolSto, uint_fast32_t poolSize, uint_fast16_t blockSize)
Definition: qf_mem.c:82
void * QMPool_get(QMPool *const me, uint_fast16_t const margin, uint_fast8_t const qs_id)
Definition: qf_mem.c:212
QMPoolCtr volatile nFree
Definition: qmpool.h:122
void * start
Definition: qmpool.h:110
void * end
Definition: qmpool.h:113
QMPoolCtr nMin
Definition: qmpool.h:130
void *volatile free_head
Definition: qmpool.h:107
void QMPool_put(QMPool *const me, void *b, uint_fast8_t const qs_id)
Definition: qf_mem.c:154
uint_fast16_t QF_getPoolMin(uint_fast8_t const poolId)
Definition: qf_mem.c:293
QMPoolCtr nTot
Definition: qmpool.h:119