QP/C  8.0.0
Real-Time Embedded Framework
Loading...
Searching...
No Matches
qf_mem.c
Go to the documentation of this file.
1//$file${src::qf::qf_mem.c} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2//
3// Model: qpc.qm
4// File: ${src::qf::qf_mem.c}
5//
6// This code has been generated by QM 7.0.0 <www.state-machine.com/qm>.
7// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
8//
9// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
10//
11// Q u a n t u m L e a P s
12// ------------------------
13// Modern Embedded Software
14//
15// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
16//
17// The QP/C software is dual-licensed under the terms of the open-source GNU
18// General Public License (GPL) or under the terms of one of the closed-
19// source Quantum Leaps commercial licenses.
20//
21// Redistributions in source code must retain this top-level comment block.
22// Plagiarizing this software to sidestep the license obligations is illegal.
23//
24// NOTE:
25// The GPL does NOT permit the incorporation of this code into proprietary
26// programs. Please contact Quantum Leaps for commercial licensing options,
27// which expressly supersede the GPL and are designed explicitly for
28// closed-source distribution.
29//
30// Quantum Leaps contact information:
31// <www.state-machine.com/licensing>
32// <info@state-machine.com>
33//
34//$endhead${src::qf::qf_mem.c} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
35#define QP_IMPL // this is QP implementation
36#include "qp_port.h" // QP port
37#include "qp_pkg.h" // QP package-scope interface
38#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
39#ifdef Q_SPY // QS software tracing enabled?
40 #include "qs_port.h" // QS port
41 #include "qs_pkg.h" // QS facilities for pre-defined trace records
42#else
43 #include "qs_dummy.h" // disable the QS software tracing
44#endif // Q_SPY
45
46Q_DEFINE_THIS_MODULE("qf_mem")
47
48//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
49// Check for the minimum required QP version
50#if (QP_VERSION < 730U) || (QP_VERSION != ((QP_RELEASE^4294967295U)%0x2710U))
51#error qpc version 7.3.0 or higher required
52#endif
53//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
54//$define${QF::QMPool} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
55
56//${QF::QMPool} ..............................................................
57
58//${QF::QMPool::init} ........................................................
59//! @public @memberof QMPool
60void QMPool_init(QMPool * const me,
61 void * const poolSto,
62 uint_fast32_t const poolSize,
63 uint_fast16_t const blockSize)
64{
67 QF_MEM_SYS();
68
69 Q_REQUIRE_INCRIT(100, poolSto != (void *)0);
70 Q_REQUIRE_INCRIT(101, poolSize >= (uint_fast32_t)sizeof(QFreeBlock));
71 Q_REQUIRE_INCRIT(102, (uint_fast16_t)(blockSize + sizeof(QFreeBlock))
72 > blockSize);
73
74 me->free_head = (QFreeBlock *)poolSto;
75
76 // find # free blocks in a memory block, NO DIVISION
77 me->blockSize = (QMPoolSize)(2U * sizeof(void *));
78 uint_fast16_t nblocks = 1U;
79 while (me->blockSize < (QMPoolSize)blockSize) {
80 me->blockSize += (QMPoolSize)sizeof(QFreeBlock);
81 ++nblocks;
82 }
83
84 // the pool buffer must fit at least one rounded-up block
85 Q_ASSERT_INCRIT(110, poolSize >= me->blockSize);
86
87 // start at the head of the free list
88 QFreeBlock *fb = me->free_head;
89 uint32_t nTot = 1U; // the last block already in the list
90
91 // chain all blocks together in a free-list...
92 for (uint_fast32_t size = poolSize - me->blockSize;
93 size >= (uint_fast32_t)me->blockSize;
94 size -= (uint_fast32_t)me->blockSize)
95 {
96 fb->next = &fb[nblocks]; // point next link to next block
97 #ifndef Q_UNSAFE
98 fb->next_dis = (uintptr_t)(~Q_PTR2UINT_CAST_(fb->next));
99 #endif
100 fb = fb->next; // advance to the next block
101 ++nTot; // one more free block in the pool
102 }
103
104 // dynamic range check
105 #if (QF_MPOOL_CTR_SIZE == 1U)
106 Q_ENSURE_INCRIT(190, nTot < 0xFFU);
107 #elif (QF_MPOOL_CTR_SIZE == 2U)
108 Q_ENSURE_INCRIT(190, nTot < 0xFFFFU);
109 #endif
110
111 fb->next = (QFreeBlock *)0; // the last link points to NULL
112
113 me->nTot = (QMPoolCtr)nTot;
114 me->nFree = me->nTot; // all blocks are free
115 me->start = (QFreeBlock *)poolSto; // the original start this pool buffer
116 me->end = fb; // the last block in this pool
117
118 #ifndef Q_UNSAFE
119 me->free_head_dis = (uintptr_t)~Q_PTR2UINT_CAST_(me->free_head);
120 me->nFree_dis = (QMPoolCtr)~me->nFree;
121 me->nMin = me->nTot; // the minimum # free blocks
122 fb->next_dis = (uintptr_t)(~Q_PTR2UINT_CAST_(fb->next));
123 #endif
124
125 QF_MEM_APP();
126 QF_CRIT_EXIT();
127}
128
129//${QF::QMPool::get} .........................................................
130//! @public @memberof QMPool
131void * QMPool_get(QMPool * const me,
132 uint_fast16_t const margin,
133 uint_fast8_t const qsId)
134{
135 #ifndef Q_SPY
136 Q_UNUSED_PAR(qsId);
137 #endif
138
141 QF_MEM_SYS();
142
143 // get volatile into temporaries
144 QFreeBlock *fb = me->free_head;
145 QMPoolCtr nFree = me->nFree;
146
147 #ifndef Q_UNSAFE
149 == (uintptr_t)~me->free_head_dis);
150 QMPoolCtr const dis = (QMPoolCtr)~me->nFree_dis;
151 Q_INVARIANT_INCRIT(302, nFree == dis);
152 #endif // ndef Q_UNSAFE
153
154 // have more free blocks than the requested margin?
155 if (nFree > (QMPoolCtr)margin) {
156 Q_ASSERT_INCRIT(310, fb != (QFreeBlock *)0);
157
158 QFreeBlock * const fb_next = fb->next; // fast temporary
159
160 #ifndef Q_UNSAFE
161 // the free block must have integrity (duplicate inverse storage)
163 == (uintptr_t)~fb->next_dis);
164 #endif // ndef Q_UNSAFE
165
166 --nFree; // one less free block
167 if (nFree == 0U) { // is the pool becoming empty?
168 // pool is becoming empty, so the next free block must be NULL
169 Q_ASSERT_INCRIT(320, fb_next == (QFreeBlock *)0);
170
171 me->nFree = 0U;
172 #ifndef Q_UNSAFE
173 me->nFree_dis = (QMPoolCtr)~0U;
174 me->nMin = 0U; // remember that the pool got empty
175 #endif // ndef Q_UNSAFE
176 }
177 else {
178 me->nFree = nFree; // update the original
179 #ifndef Q_UNSAFE
180 me->nFree_dis = (QMPoolCtr)~nFree;
181
182 // The pool is not empty, so the next free-block pointer
183 // must be in range.
185 (me->start <= fb_next) && (fb_next <= me->end));
186
187 // is the # free blocks the new minimum so far?
188 if (me->nMin > nFree) {
189 me->nMin = nFree; // remember the minimum so far
190 }
191 #endif // ndef Q_UNSAFE
192 }
193
194 me->free_head = fb_next; // set the head to the next free block
195 #ifndef Q_UNSAFE
196 me->free_head_dis = (uintptr_t)(~Q_PTR2UINT_CAST_(fb_next));
197 #endif // ndef Q_UNSAFE
198
199 QS_BEGIN_PRE(QS_QF_MPOOL_GET, qsId)
200 QS_TIME_PRE(); // timestamp
201 QS_OBJ_PRE(me); // this memory pool
202 QS_MPC_PRE(nFree); // # of free blocks in the pool
203 #ifndef Q_UNSAFE
204 QS_MPC_PRE(me->nMin); // min # free blocks ever in the pool
205 #else
206 QS_MPC_PRE(0U); // min # free blocks (not available)
207 #endif // ndef Q_UNSAFE
208 QS_END_PRE()
209 }
210 else { // don't have enough free blocks at this point
211 fb = (QFreeBlock *)0;
212
213 QS_BEGIN_PRE(QS_QF_MPOOL_GET_ATTEMPT, qsId)
214 QS_TIME_PRE(); // timestamp
215 QS_OBJ_PRE(me); // this memory pool
216 QS_MPC_PRE(nFree); // # of free blocks in the pool
217 QS_MPC_PRE(margin); // the requested margin
218 QS_END_PRE()
219 }
220
221 QF_MEM_APP();
222 QF_CRIT_EXIT();
223
224 return fb; // return the block or NULL pointer to the caller
225}
226
227//${QF::QMPool::put} .........................................................
228//! @public @memberof QMPool
229void QMPool_put(QMPool * const me,
230 void * const block,
231 uint_fast8_t const qsId)
232{
233 #ifndef Q_SPY
234 Q_UNUSED_PAR(qsId);
235 #endif
236
237 QFreeBlock * const fb = (QFreeBlock *)block;
238
241 QF_MEM_SYS();
242
243 // get volatile into temporaries
244 QFreeBlock * const free_head = me->free_head;
245 QMPoolCtr nFree = me->nFree;
246
247 #ifndef Q_UNSAFE
249 == (uintptr_t)~me->free_head_dis);
250 QMPoolCtr const dis = (QMPoolCtr)~me->nFree_dis;
251 Q_INVARIANT_INCRIT(402, nFree == dis);
252
253 Q_REQUIRE_INCRIT(410, nFree < me->nTot);
254 Q_REQUIRE_INCRIT(411, (me->start <= fb) && (fb <= me->end));
255
256 // the block must not be in the pool already
258 != (uintptr_t)~fb->next_dis);
259 #endif // ndef Q_UNSAFE
260
261 ++nFree; // one more free block in this pool
262
263 me->free_head = fb; // set as new head of the free list
264 me->nFree = nFree;
265 fb->next = free_head; // link into the list
266 #ifndef Q_UNSAFE
267 me->free_head_dis = (uintptr_t)(~Q_PTR2UINT_CAST_(fb));
268 me->nFree_dis = (QMPoolCtr)~nFree;
269 fb->next_dis = (uintptr_t)(~Q_PTR2UINT_CAST_(free_head));
270 #endif
271
272 QS_BEGIN_PRE(QS_QF_MPOOL_PUT, qsId)
273 QS_TIME_PRE(); // timestamp
274 QS_OBJ_PRE(me); // this memory pool
275 QS_MPC_PRE(nFree); // the # free blocks in the pool
276 QS_END_PRE()
277
278 QF_MEM_APP();
279 QF_CRIT_EXIT();
280}
281//$enddef${QF::QMPool} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
uint16_t QMPoolSize
The data type to store the block-size based on the macro QF_MPOOL_SIZ_SIZE.
Definition qmpool.h:48
uint16_t QMPoolCtr
The data type to store the block-counter based on the macro QF_MPOOL_CTR_SIZE.
Definition qmpool.h:58
#define QF_MEM_APP()
Definition qp.h:1280
#define Q_UNUSED_PAR(par_)
Helper macro to clearly mark unused parameters of functions.
Definition qp.h:525
#define QF_MEM_SYS()
Definition qp.h:1275
Internal (package scope) QP/C interface.
#define Q_PTR2UINT_CAST_(ptr_)
Definition qp_pkg.h:95
Sample QP/C port.
#define QS_OBJ_PRE(obj_)
Definition qs_dummy.h:150
#define QS_TIME_PRE()
Definition qs_dummy.h:147
#define QS_MPC_PRE(ctr_)
Definition qs_dummy.h:153
#define QS_END_PRE()
Definition qs_dummy.h:142
#define QS_BEGIN_PRE(rec_, qsId_)
Definition qs_dummy.h:141
Sample QS/C port.
QP Functional Safety (FuSa) Subsystem.
#define QF_CRIT_ENTRY()
Definition qsafe.h:50
#define Q_ASSERT_INCRIT(id_, expr_)
Definition qsafe.h:64
#define Q_INVARIANT_INCRIT(id_, expr_)
Definition qsafe.h:146
#define Q_ENSURE_INCRIT(id_, expr_)
Definition qsafe.h:137
#define QF_CRIT_EXIT()
Definition qsafe.h:54
#define Q_REQUIRE_INCRIT(id_, expr_)
Definition qsafe.h:128
#define QF_CRIT_STAT
Definition qsafe.h:46
Structure representing a free block in QMPool.
Definition qmpool.h:73
uintptr_t next_dis
Duplicate inverse storage for the next pointer (QP FuSa Subsystem)
Definition qmpool.h:81
struct QFreeBlock * next
Link to the next memory block.
Definition qmpool.h:77
Native QF Memory Pool.
Definition qmpool.h:90
QMPoolCtr volatile nFree
Number of free memory blocks remaining in the pool at this point.
Definition qmpool.h:109
QMPoolSize blockSize
Memory block size [bytes] held by this fixed-size pool.
Definition qmpool.h:103
QMPoolCtr nFree_dis
Definition qmpool.h:123
QFreeBlock * end
End of the memory managed by this memory pool.
Definition qmpool.h:97
QMPoolCtr nMin
Minimum number of free blocks ever present in this pool.
Definition qmpool.h:113
QFreeBlock *volatile free_head
Head of linked list of free memory blocks.
Definition qmpool.h:100
QFreeBlock * start
Start of the memory managed by this memory pool.
Definition qmpool.h:94
uintptr_t free_head_dis
Definition qmpool.h:118
QMPoolCtr nTot
Total number of memory blocks in this pool.
Definition qmpool.h:106