QP/C  7.4.0-rc.3
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 6.2.0 <www.state-machine.com/qm>.
7// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
8//
9// This code is covered by the following QP license:
10// License # : LicenseRef-QL-dual
11// Issued to : Any user of the QP/C real-time embedded framework
12// Framework(s) : qpc
13// Support ends : 2025-12-31
14// License scope:
15//
16// Copyright (C) 2005 Quantum Leaps, LLC <state-machine.com>.
17//
18// Q u a n t u m L e a P s
19// ------------------------
20// Modern Embedded Software
21//
22// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
23//
24// This software is dual-licensed under the terms of the open source GNU
25// General Public License version 3 (or any later version), or alternatively,
26// under the terms of one of the closed source Quantum Leaps commercial
27// licenses.
28//
29// The terms of the open source GNU General Public License version 3
30// can be found at: <www.gnu.org/licenses/gpl-3.0>
31//
32// The terms of the closed source Quantum Leaps commercial licenses
33// can be found at: <www.state-machine.com/licensing>
34//
35// Redistributions in source code must retain this top-level comment block.
36// Plagiarizing this software to sidestep the license obligations is illegal.
37//
38// Contact information:
39// <www.state-machine.com/licensing>
40// <info@state-machine.com>
41//
42//$endhead${src::qf::qf_mem.c} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
43#define QP_IMPL // this is QP implementation
44#include "qp_port.h" // QP port
45#include "qp_pkg.h" // QP package-scope interface
46#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
47#ifdef Q_SPY // QS software tracing enabled?
48 #include "qs_port.h" // QS port
49 #include "qs_pkg.h" // QS facilities for pre-defined trace records
50#else
51 #include "qs_dummy.h" // disable the QS software tracing
52#endif // Q_SPY
53
54Q_DEFINE_THIS_MODULE("qf_mem")
55
56//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
57// Check for the minimum required QP version
58#if (QP_VERSION < 730U) || (QP_VERSION != ((QP_RELEASE^4294967295U)%0x2710U))
59#error qpc version 7.3.0 or higher required
60#endif
61//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
62//$define${QF::QMPool} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
63
64//${QF::QMPool} ..............................................................
65
66//${QF::QMPool::init} ........................................................
67//! @public @memberof QMPool
68void QMPool_init(QMPool * const me,
69 void * const poolSto,
70 uint_fast32_t const poolSize,
71 uint_fast16_t const blockSize)
72{
75 QF_MEM_SYS();
76
77 Q_REQUIRE_INCRIT(100, (poolSto != (void *)0)
78 && (poolSize >= (uint_fast32_t)sizeof(QFreeBlock))
79 && ((uint_fast16_t)(blockSize + sizeof(QFreeBlock)) > blockSize));
80
81 me->free_head = (QFreeBlock *)poolSto;
82
83 // find # free blocks in a memory block, NO DIVISION
84 me->blockSize = (QMPoolSize)sizeof(QFreeBlock);
85 uint_fast16_t nblocks = 1U;
86 while (me->blockSize < (QMPoolSize)blockSize) {
87 me->blockSize += (QMPoolSize)sizeof(QFreeBlock);
88 ++nblocks;
89 }
90
91 // the pool buffer must fit at least one rounded-up block
92 Q_ASSERT_INCRIT(110, poolSize >= me->blockSize);
93
94 // start at the head of the free list
95 QFreeBlock *fb = me->free_head;
96 uint32_t nTot = 1U; // the last block already in the list
97
98 // chain all blocks together in a free-list...
99 for (uint_fast32_t size = poolSize - me->blockSize;
100 size >= (uint_fast32_t)me->blockSize;
101 size -= (uint_fast32_t)me->blockSize)
102 {
103 fb->next = &fb[nblocks]; // point next link to next block
104 #ifndef Q_UNSAFE
105 fb->next_dis = (uintptr_t)(~Q_UINTPTR_CAST_(fb->next));
106 #endif
107 fb = fb->next; // advance to the next block
108 ++nTot; // one more free block in the pool
109 }
110
111 // dynamic range check
112 #if (QF_MPOOL_CTR_SIZE == 1U)
113 Q_ENSURE_INCRIT(190, nTot < 0xFFU);
114 #elif (QF_MPOOL_CTR_SIZE == 2U)
115 Q_ENSURE_INCRIT(190, nTot < 0xFFFFU);
116 #endif
117
118 fb->next = (QFreeBlock *)0; // the last link points to NULL
119 #ifndef Q_UNSAFE
120 fb->next_dis = (uintptr_t)(~Q_UINTPTR_CAST_(fb->next));
121 #endif
122
123 me->nTot = (QMPoolCtr)nTot;
124 me->nFree = me->nTot; // all blocks are free
125 me->nMin = me->nTot; // the minimum # free blocks
126 me->start = (QFreeBlock *)poolSto; // the original start this pool buffer
127 me->end = fb; // the last block in this pool
128
129 QF_MEM_APP();
130 QF_CRIT_EXIT();
131}
132
133//${QF::QMPool::get} .........................................................
134//! @public @memberof QMPool
135void * QMPool_get(QMPool * const me,
136 uint_fast16_t const margin,
137 uint_fast8_t const qsId)
138{
139 #ifndef Q_SPY
140 Q_UNUSED_PAR(qsId);
141 #endif
142
145 QF_MEM_SYS();
146
147 // have more free blocks than the requested margin?
148 QFreeBlock *fb;
149 if (me->nFree > (QMPoolCtr)margin) {
150 fb = me->free_head; // get a free block
151
152 // a free block must be valid
153 Q_ASSERT_INCRIT(300, fb != (QFreeBlock *)0);
154
155 QFreeBlock * const fb_next = fb->next; // fast temporary
156
157 // the free block must have integrity (duplicate inverse storage)
159 == (uintptr_t)~fb->next_dis);
160
161 --me->nFree; // one less free block
162 if (me->nFree == 0U) { // is the pool becoming empty?
163 // pool is becoming empty, so the next free block must be NULL
164 Q_ASSERT_INCRIT(320, fb_next == (QFreeBlock *)0);
165
166 me->nMin = 0U; // remember that the pool got empty
167 }
168 else {
169 // invariant:
170 // The pool is not empty, so the next free-block pointer,
171 // so the next free block must be in range.
172
173 // NOTE: The next free block pointer can fall out of range
174 // when the client code writes past the memory block, thus
175 // corrupting the next block.
176 Q_ASSERT_INCRIT(330,
177 (me->start <= fb_next) && (fb_next <= me->end));
178
179 // is the # free blocks the new minimum so far?
180 if (me->nMin > me->nFree) {
181 me->nMin = me->nFree; // remember the new minimum
182 }
183 }
184
185 me->free_head = fb_next; // set the head to the next free block
186
187 QS_BEGIN_PRE_(QS_QF_MPOOL_GET, qsId)
188 QS_TIME_PRE_(); // timestamp
189 QS_OBJ_PRE_(me); // this memory pool
190 QS_MPC_PRE_(me->nFree); // # of free blocks in the pool
191 QS_MPC_PRE_(me->nMin); // min # free blocks ever in the pool
192 QS_END_PRE_()
193 }
194 else { // don't have enough free blocks at this point
195 fb = (QFreeBlock *)0;
196
197 QS_BEGIN_PRE_(QS_QF_MPOOL_GET_ATTEMPT, qsId)
198 QS_TIME_PRE_(); // timestamp
199 QS_OBJ_PRE_(me); // this memory pool
200 QS_MPC_PRE_(me->nFree); // # of free blocks in the pool
201 QS_MPC_PRE_(margin); // the requested margin
202 QS_END_PRE_()
203 }
204
205 QF_MEM_APP();
206 QF_CRIT_EXIT();
207
208 return fb; // return the block or NULL pointer to the caller
209}
210
211//${QF::QMPool::put} .........................................................
212//! @public @memberof QMPool
213void QMPool_put(QMPool * const me,
214 void * const block,
215 uint_fast8_t const qsId)
216{
217 #ifndef Q_SPY
218 Q_UNUSED_PAR(qsId);
219 #endif
220
221 QFreeBlock * const fb = (QFreeBlock *)block;
222
225 QF_MEM_SYS();
226
227 Q_REQUIRE_INCRIT(200, (me->nFree < me->nTot)
228 && (me->start <= fb) && (fb <= me->end));
229
230 fb->next = me->free_head; // link into list
231 #ifndef Q_UNSAFE
232 fb->next_dis = (uintptr_t)(~Q_UINTPTR_CAST_(fb->next));
233 #endif
234
235 // set as new head of the free list
236 me->free_head = fb;
237
238 ++me->nFree; // one more free block in this pool
239
240 QS_BEGIN_PRE_(QS_QF_MPOOL_PUT, qsId)
241 QS_TIME_PRE_(); // timestamp
242 QS_OBJ_PRE_(me); // this memory pool
243 QS_MPC_PRE_(me->nFree); // the # free blocks in the pool
244 QS_END_PRE_()
245
246 QF_MEM_APP();
247 QF_CRIT_EXIT();
248}
249//$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:56
uint16_t QMPoolCtr
The data type to store the block-counter based on the macro QF_MPOOL_CTR_SIZE.
Definition qmpool.h:66
#define QF_MEM_APP()
Definition qp.h:1288
#define Q_UNUSED_PAR(par_)
Helper macro to clearly mark unused parameters of functions.
Definition qp.h:536
#define QF_MEM_SYS()
Definition qp.h:1283
Internal (package scope) QP/C interface.
#define Q_UINTPTR_CAST_(ptr_)
Definition qp_pkg.h:97
Sample QP/C port.
@ QS_QF_MPOOL_GET_ATTEMPT
attempt to get a memory block failed
Definition qs.h:148
#define QS_TIME_PRE_()
Definition qs.h:450
@ QS_QF_MPOOL_PUT
a memory block was returned to memory pool
Definition qs.h:114
@ QS_QF_MPOOL_GET
a memory block was removed from memory pool
Definition qs.h:113
QS/C package-scope interface.
Sample QS/C port.
QP Functional Safety (FuSa) Subsystem.
#define QF_CRIT_ENTRY()
Definition qsafe.h:58
#define Q_ASSERT_INCRIT(id_, expr_)
Definition qsafe.h:72
#define Q_INVARIANT_INCRIT(id_, expr_)
Definition qsafe.h:154
#define Q_ENSURE_INCRIT(id_, expr_)
Definition qsafe.h:145
#define QF_CRIT_EXIT()
Definition qsafe.h:62
#define Q_REQUIRE_INCRIT(id_, expr_)
Definition qsafe.h:136
#define QF_CRIT_STAT
Definition qsafe.h:54
Structure representing a free block in QMPool.
Definition qmpool.h:81
uintptr_t next_dis
Duplicate inverse storage for the next pointer (QP FuSa Subsystem)
Definition qmpool.h:89
struct QFreeBlock * next
Link to the next memory block.
Definition qmpool.h:85
Native QF Memory Pool.
Definition qmpool.h:98
QMPoolCtr volatile nFree
Number of free memory blocks remaining in the pool at this point.
Definition qmpool.h:117
QMPoolSize blockSize
Memory block size [bytes] held by this fixed-size pool.
Definition qmpool.h:111
QFreeBlock * end
End of the memory managed by this memory pool.
Definition qmpool.h:105
QMPoolCtr nMin
Minimum number of free blocks ever present in this pool.
Definition qmpool.h:120
QFreeBlock *volatile free_head
Head of linked list of free memory blocks.
Definition qmpool.h:108
QFreeBlock * start
Start of the memory managed by this memory pool.
Definition qmpool.h:102
QMPoolCtr nTot
Total number of memory blocks in this pool.
Definition qmpool.h:114