QP/C  8.0.2
Real-Time Event Framework
Loading...
Searching...
No Matches
qf_mem.c
Go to the documentation of this file.
1//============================================================================
2// QP/C Real-Time Event Framework (RTEF)
3//
4// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
5//
6// Q u a n t u m L e a P s
7// ------------------------
8// Modern Embedded Software
9//
10// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
11//
12// This software is dual-licensed under the terms of the open-source GNU
13// General Public License (GPL) or under the terms of one of the closed-
14// source Quantum Leaps commercial licenses.
15//
16// Redistributions in source code must retain this top-level comment block.
17// Plagiarizing this software to sidestep the license obligations is illegal.
18//
19// NOTE:
20// The GPL does NOT permit the incorporation of this code into proprietary
21// programs. Please contact Quantum Leaps for commercial licensing options,
22// which expressly supersede the GPL and are designed explicitly for
23// closed-source distribution.
24//
25// Quantum Leaps contact information:
26// <www.state-machine.com/licensing>
27// <info@state-machine.com>
28//============================================================================
29#define QP_IMPL // this is QP implementation
30#include "qp_port.h" // QP port
31#include "qp_pkg.h" // QP package-scope interface
32#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
33#ifdef Q_SPY // QS software tracing enabled?
34 #include "qs_port.h" // QS port
35 #include "qs_pkg.h" // QS package-scope internal interface
36#else
37 #include "qs_dummy.h" // disable the QS software tracing
38#endif // Q_SPY
39
40Q_DEFINE_THIS_MODULE("qf_mem")
41
42//............................................................................
43//! @public @memberof QMPool
44void QMPool_init(QMPool * const me,
45 void * const poolSto,
46 uint_fast32_t const poolSize,
47 uint_fast16_t const blockSize)
48{
51
52 Q_REQUIRE_INCRIT(100, poolSto != (void *)0);
53
54 me->freeHead = (void * *)poolSto;
55
56 // find # free links in a memory block, see NOTE1
57 me->blockSize = (QMPoolSize)(2U * sizeof(void *));
58 uint_fast16_t inext = 2U; // # index of the next block
59 while (me->blockSize < (QMPoolSize)blockSize) {
60 me->blockSize += (QMPoolSize)sizeof(void *);
61 ++inext;
62 }
63
64 // the pool buffer must fit at least one rounded-up block
65 Q_ASSERT_INCRIT(110, poolSize >= me->blockSize);
66
67 // start at the head of the free list
68 void * *pfb = me->freeHead; // pointer to free block
69 uint32_t nTot = 1U; // the last block already in the list
70
71 // chain all blocks together in a free-list...
72 for (uint_fast32_t size = poolSize - me->blockSize;
73 size >= (uint_fast32_t)me->blockSize;
74 size -= (uint_fast32_t)me->blockSize)
75 {
76 pfb[0] = &pfb[inext]; // set the next link to next free block
77 pfb = pfb[0]; // advance to the next block
78 ++nTot; // one more free block in the pool
79 }
80 pfb[0] = (void * *)0; // the last link points to NULL
81
82 // dynamic range check
83#if (QF_MPOOL_CTR_SIZE == 1U)
84 Q_ASSERT_INCRIT(190, nTot < 0xFFU);
85#elif (QF_MPOOL_CTR_SIZE == 2U)
86 Q_ASSERT_INCRIT(190, nTot < 0xFFFFU);
87#endif
88
89 me->nTot = (QMPoolCtr)nTot;
90 me->nFree = me->nTot; // all blocks are free
91 me->start = (void * *)poolSto; // the original start this pool buffer
92 me->end = pfb; // the last block in this pool
93 me->nMin = me->nTot; // the minimum # free blocks
94
96}
97
98//............................................................................
99//! @public @memberof QMPool
100void * QMPool_get(QMPool * const me,
101 uint_fast16_t const margin,
102 uint_fast8_t const qsId)
103{
104#ifndef Q_SPY
105 Q_UNUSED_PAR(qsId);
106#endif
107
110
111 // get volatile into temporaries
112 void * *pfb = me->freeHead; // pointer to free block
113 QMPoolCtr nFree = me->nFree;
114
115 // have more free blocks than the requested margin?
116 if (nFree > (QMPoolCtr)margin) {
117 Q_ASSERT_INCRIT(310, pfb != (void * *)0);
118
119 void * * const pfb_next = pfb[0]; // fast temporary
120
121 --nFree; // one less free block
122 if (nFree == 0U) { // is the pool becoming empty?
123 // pool is becoming empty, so the next free block must be NULL
124 Q_ASSERT_INCRIT(320, pfb_next == (void * *)0);
125
126 me->nFree = 0U; // no more free blocks
127 me->nMin = 0U; // remember that the pool got empty
128 }
129 else { // the pool is NOT empty
130
131 // the next free-block pointer must be in range
132 Q_ASSERT_INCRIT(330,
133 (me->start <= pfb_next) && (pfb_next <= me->end));
134
135 me->nFree = nFree; // update the original
136 if (me->nMin > nFree) { // is this the new minimum?
137 me->nMin = nFree; // remember the minimum so far
138 }
139 }
140
141 me->freeHead = pfb_next; // set the head to the next free block
142
143 // change the allocated block contents so that it is different
144 // than a free block inside the pool.
145 pfb[0] = &me->end[1]; // invalid location beyond the end
146
147 QS_BEGIN_PRE(QS_QF_MPOOL_GET, qsId)
148 QS_TIME_PRE(); // timestamp
149 QS_OBJ_PRE(me); // this memory pool
150 QS_MPC_PRE(nFree); // # free blocks in the pool
151 QS_MPC_PRE(me->nMin); // min # free blocks ever in the pool
152 QS_END_PRE()
153 }
154 else { // don't have enough free blocks at this point
155 pfb = (void * *)0;
156
157 QS_BEGIN_PRE(QS_QF_MPOOL_GET_ATTEMPT, qsId)
158 QS_TIME_PRE(); // timestamp
159 QS_OBJ_PRE(me); // this memory pool
160 QS_MPC_PRE(nFree); // # free blocks in the pool
161 QS_MPC_PRE(margin); // the requested margin
162 QS_END_PRE()
163 }
164
165 QF_CRIT_EXIT();
166
167 return (void *)pfb; // return the block or NULL pointer to the caller
168}
169
170//............................................................................
171//! @public @memberof QMPool
172void QMPool_put(QMPool * const me,
173 void * const block,
174 uint_fast8_t const qsId)
175{
176#ifndef Q_SPY
177 Q_UNUSED_PAR(qsId);
178#endif
179
180 void * * const pfb = (void * *)block; // pointer to free block
181
184
185 // get volatile into temporaries
186 void * * const freeHead = me->freeHead;
187 QMPoolCtr nFree = me->nFree;
188
189 Q_REQUIRE_INCRIT(400, nFree < me->nTot);
190 Q_REQUIRE_INCRIT(410, (me->start <= pfb) && (pfb <= me->end));
191
192 ++nFree; // one more free block in this pool
193
194 me->freeHead = pfb; // set as new head of the free list
195 me->nFree = nFree;
196 pfb[0] = freeHead; // link into the list
197
198 QS_BEGIN_PRE(QS_QF_MPOOL_PUT, qsId)
199 QS_TIME_PRE(); // timestamp
200 QS_OBJ_PRE(me); // this memory pool
201 QS_MPC_PRE(nFree); // the # free blocks in the pool
202 QS_END_PRE()
203
204 QF_CRIT_EXIT();
205}
206
207//============================================================================
208// NOTE1:
209// The memory buffer for the pool is organized as an array of void* pointers
210// (see void * data type). These pointers are used to form a linked-list
211// of free blocks in the pool. The first location pfb[0] is the actual link.
212// The second location pfb[1] is used in SafeQP as the redundant "duplicate
213// storage" for the link at pfb[0]. Even though the "duplicate storage" is NOT
214// used in this QP edition, the minimum number of number of void* pointers
215// (void * data type) inside a memory block is still kept at 2 to maintain
216// the same policy for sizing the memory blocks.
uint16_t QMPoolSize
The data type to store the block-size based on the macro QF_MPOOL_SIZ_SIZE.
Definition qmpool.h:47
uint16_t QMPoolCtr
The data type to store the block-counter based on the macro QF_MPOOL_CTR_SIZE.
Definition qmpool.h:57
#define Q_UNUSED_PAR(par_)
Helper macro to clearly mark unused parameters of functions.
Definition qp.h:96
Internal (package scope) QP/C interface.
Sample QP/C port.
#define QS_OBJ_PRE(obj_)
Definition qs_dummy.h:149
#define QS_TIME_PRE()
Definition qs_dummy.h:146
#define QS_MPC_PRE(ctr_)
Definition qs_dummy.h:152
#define QS_END_PRE()
Definition qs_dummy.h:141
#define QS_BEGIN_PRE(rec_, qsId_)
Definition qs_dummy.h:140
Sample QS/C port.
QP Functional Safety (FuSa) Subsystem.
#define QF_CRIT_ENTRY()
Definition qsafe.h:39
#define Q_ASSERT_INCRIT(id_, expr_)
General-purpose assertion with user-specified ID number (in critical section)
Definition qsafe.h:49
#define QF_CRIT_EXIT()
Definition qsafe.h:43
#define Q_REQUIRE_INCRIT(id_, expr_)
Assertion for checking a precondition (in critical section)
Definition qsafe.h:86
#define QF_CRIT_STAT
Definition qsafe.h:35
Native QF Memory Pool.
Definition qmpool.h:66
void **volatile freeHead
Definition qmpool.h:69
void ** end
End of the memory managed by this memory pool.
Definition qmpool.h:68
void QMPool_put(QMPool *const me, void *const block, uint_fast8_t const qsId)
Recycles a memory block back to a memory pool.
Definition qf_mem.c:172
void * QMPool_get(QMPool *const me, uint_fast16_t const margin, uint_fast8_t const qsId)
Obtain a memory block from a memory pool.
Definition qf_mem.c:100
void ** start
Start of the memory managed by this memory pool.
Definition qmpool.h:67
QMPoolCtr volatile nFree
Number of free memory blocks remaining in the pool at this point.
Definition qmpool.h:72
QMPoolCtr nMin
Minimum number of free blocks ever present in this pool.
Definition qmpool.h:73
QMPoolCtr nTot
Total number of memory blocks in this pool.
Definition qmpool.h:71