QP/C++  8.0.0
Real-Time Embedded Framework
Loading...
Searching...
No Matches
qf_mem.cpp
Go to the documentation of this file.
1//$file${src::qf::qf_mem.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2//
3// Model: qpcpp.qm
4// File: ${src::qf::qf_mem.cpp}
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
18// GNU 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.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
35#define QP_IMPL // this is QP implementation
36#include "qp_port.hpp" // QP port
37#include "qp_pkg.hpp" // 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.hpp" // QS port
41 #include "qs_pkg.hpp" // QS facilities for pre-defined trace records
42#else
43 #include "qs_dummy.hpp" // disable the QS software tracing
44#endif // Q_SPY
45
46// unnamed namespace for local definitions with internal linkage
47namespace {
48Q_DEFINE_THIS_MODULE("qf_mem")
49} // unnamed namespace
50
51//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
52// Check for the minimum required QP version
53#if (QP_VERSION < 730U) || (QP_VERSION != ((QP_RELEASE^4294967295U)%0x2710U))
54#error qpcpp version 7.3.0 or higher required
55#endif
56//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
57//$define${QF::QMPool} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
58namespace QP {
59
60//${QF::QMPool} ..............................................................
61
62//${QF::QMPool::init} ........................................................
64 void * const poolSto,
65 std::uint_fast32_t const poolSize,
66 std::uint_fast16_t const blockSize) noexcept
67{
70 QF_MEM_SYS();
71
72 Q_REQUIRE_INCRIT(100, poolSto != nullptr);
74 poolSize >= static_cast<std::uint_fast32_t>(sizeof(QFreeBlock)));
76 static_cast<std::uint_fast16_t>(blockSize + sizeof(QFreeBlock))
77 > blockSize);
78
79 m_free_head = static_cast<QFreeBlock *>(poolSto);
80
81 // find # free blocks in a memory block, NO DIVISION
82 m_blockSize = static_cast<QMPoolSize>(2U * sizeof(void *));
83 std::uint_fast16_t nblocks = 1U;
84 while (m_blockSize < static_cast<QMPoolSize>(blockSize)) {
85 m_blockSize += static_cast<QMPoolSize>(sizeof(QFreeBlock));
86 ++nblocks;
87 }
88
89 // the pool buffer must fit at least one rounded-up block
90 Q_ASSERT_INCRIT(110, poolSize >= m_blockSize);
91
92 // start at the head of the free list
93 QFreeBlock *fb = m_free_head;
94 std::uint32_t nTot = 1U; // the last block already in the list
95
96 // chain all blocks together in a free-list...
97 for (std::uint_fast32_t size = poolSize - m_blockSize;
98 size >= static_cast<std::uint_fast32_t>(m_blockSize);
99 size -= static_cast<std::uint_fast32_t>(m_blockSize))
100 {
101 fb->m_next = &fb[nblocks]; // point next link to next block
102 #ifndef Q_UNSAFE
103 fb->m_next_dis = ~Q_PTR2UINT_CAST_(fb->m_next);
104 #endif
105 fb = fb->m_next; // advance to the next block
106 ++nTot; // one more free block in the pool
107 }
108
109 // dynamic range check
110 #if (QF_MPOOL_CTR_SIZE == 1U)
111 Q_ENSURE_INCRIT(190, nTot < 0xFFU);
112 #elif (QF_MPOOL_CTR_SIZE == 2U)
113 Q_ENSURE_INCRIT(190, nTot < 0xFFFFU);
114 #endif
115
116 fb->m_next = nullptr; // the last link points to NULL
117
118 m_nTot = static_cast<QMPoolCtr>(nTot);
119 m_nFree = m_nTot; // all blocks are free
120 m_start = static_cast<QFreeBlock *>(poolSto); // original start
121 m_end = fb; // the last block in this pool
122
123 #ifndef Q_UNSAFE
124 m_free_head_dis =
125 static_cast<std::uintptr_t>(~Q_PTR2UINT_CAST_(m_free_head));
126 m_nFree_dis = static_cast<QMPoolCtr>(~m_nFree);
127 m_nMin = m_nTot; // the minimum # free blocks
128 fb->m_next_dis = ~Q_PTR2UINT_CAST_(fb->m_next);
129 #endif
130
131 QF_MEM_APP();
132 QF_CRIT_EXIT();
133}
134
135//${QF::QMPool::get} .........................................................
137 std::uint_fast16_t const margin,
138 std::uint_fast8_t const qsId) noexcept
139{
140 #ifndef Q_SPY
141 Q_UNUSED_PAR(qsId);
142 #endif
143
146 QF_MEM_SYS();
147
148 // get volatile into temporaries
149 QFreeBlock *fb = m_free_head;
150 QMPoolCtr nFree = m_nFree;
151
152 #ifndef Q_UNSAFE
154 == static_cast<std::uintptr_t>(~m_free_head_dis));
155 Q_INVARIANT_INCRIT(302, nFree == static_cast<QMPoolCtr>(~m_nFree_dis));
156 #endif // ndef Q_UNSAFE
157
158 // have more free blocks than the requested margin?
159 if (nFree > static_cast<QMPoolCtr>(margin)) {
160 Q_ASSERT_INCRIT(310, fb != nullptr);
161
162 QFreeBlock * const fb_next = fb->m_next;
163
164 #ifndef Q_UNSAFE
165 // the free block must have integrity (duplicate inverse storage)
167 == static_cast<std::uintptr_t>(~fb->m_next_dis));
168 #endif // ndef Q_UNSAFE
169
170 --nFree; // one less free block
171 if (nFree == 0U) { // is the pool becoming empty?
172 // pool is becoming empty, so the next free block must be NULL
173 Q_ASSERT_INCRIT(320, fb_next == nullptr);
174
175 m_nFree = 0U;
176 #ifndef Q_UNSAFE
177 m_nFree_dis = static_cast<QMPoolCtr>(~m_nFree);
178 m_nMin = 0U; // remember that the pool got empty
179 #endif // ndef Q_UNSAFE
180 }
181 else {
182 m_nFree = nFree; // update the original
183 #ifndef Q_UNSAFE
184 m_nFree_dis = static_cast<QMPoolCtr>(~nFree);
185
186 // The pool is not empty, so the next free-block pointer
187 // must be in range.
189 QF_PTR_RANGE_(fb_next, m_start, m_end));
190
191 // is the # free blocks the new minimum so far?
192 if (m_nMin > nFree) {
193 m_nMin = nFree; // remember the minimum so far
194 }
195 #endif // ndef Q_UNSAFE
196 }
197
198 m_free_head = fb_next; // set the head to the next free block
199 #ifndef Q_UNSAFE
200 m_free_head_dis =
201 static_cast<std::uintptr_t>(~Q_PTR2UINT_CAST_(fb_next));
202 #endif // ndef Q_UNSAFE
203
204 QS_BEGIN_PRE(QS_QF_MPOOL_GET, qsId)
205 QS_TIME_PRE(); // timestamp
206 QS_OBJ_PRE(this); // this memory pool
207 QS_MPC_PRE(nFree); // # of free blocks in the pool
208 #ifndef Q_UNSAFE
209 QS_MPC_PRE(m_nMin); // min # free blocks ever in the pool
210 #else
211 QS_MPC_PRE(0U); // min # free blocks (not available)
212 #endif // ndef Q_UNSAFE
213 QS_END_PRE()
214 }
215 else { // don't have enough free blocks at this point
216 fb = nullptr;
217
218 QS_BEGIN_PRE(QS_QF_MPOOL_GET_ATTEMPT, qsId)
219 QS_TIME_PRE(); // timestamp
220 QS_OBJ_PRE(this); // this memory pool
221 QS_MPC_PRE(nFree); // # of free blocks in the pool
222 QS_MPC_PRE(margin); // the requested margin
223 QS_END_PRE()
224 }
225
226 QF_MEM_APP();
227 QF_CRIT_EXIT();
228
229 return fb; // return the block or nullptr to the caller
230}
231
232//${QF::QMPool::put} .........................................................
234 void * const block,
235 std::uint_fast8_t const qsId) noexcept
236{
237 #ifndef Q_SPY
238 Q_UNUSED_PAR(qsId);
239 #endif
240
241 QFreeBlock * const fb = static_cast<QFreeBlock *>(block);
242
245 QF_MEM_SYS();
246
247 // get volatile into temporaries
248 QFreeBlock * const free_head = m_free_head;
249 QMPoolCtr nFree = m_nFree;
250
251 #ifndef Q_UNSAFE
253 == static_cast<std::uintptr_t>(~m_free_head_dis));
254 Q_INVARIANT_INCRIT(402, nFree == static_cast<QMPoolCtr>(~m_nFree_dis));
255
256 Q_REQUIRE_INCRIT(410, nFree < m_nTot);
257 Q_REQUIRE_INCRIT(411, QF_PTR_RANGE_(fb, m_start, m_end));
258
259 // the block must not be in the pool already
261 != static_cast<std::uintptr_t>(~fb->m_next_dis));
262 #endif // ndef Q_UNSAFE
263
264 ++nFree; // one more free block in this pool
265
266 m_free_head = fb; // set as new head of the free list
267 m_nFree = nFree;
268 fb->m_next = free_head; // link into the list
269 #ifndef Q_UNSAFE
270 m_free_head_dis = static_cast<std::uintptr_t>(~Q_PTR2UINT_CAST_(fb));
271 m_nFree_dis = static_cast<QMPoolCtr>(~nFree);
272 fb->m_next_dis = static_cast<std::uintptr_t>(~Q_PTR2UINT_CAST_(free_head));
273 #endif
274
275 QS_BEGIN_PRE(QS_QF_MPOOL_PUT, qsId)
276 QS_TIME_PRE(); // timestamp
277 QS_OBJ_PRE(this); // this memory pool
278 QS_MPC_PRE(nFree); // the # free blocks in the pool
279 QS_END_PRE()
280
281 QF_MEM_APP();
282 QF_CRIT_EXIT();
283}
284
285//${QF::QMPool::getBlockSize} ................................................
287 return m_blockSize;
288}
289
290} // namespace QP
291//$enddef${QF::QMPool} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Structure representing a free block in QP::QMPool.
Definition qmpool.hpp:77
QFreeBlock * m_next
Definition qmpool.hpp:79
std::uintptr_t m_next_dis
Definition qmpool.hpp:82
void * get(std::uint_fast16_t const margin, std::uint_fast8_t const qsId) noexcept
Definition qf_mem.cpp:136
void init(void *const poolSto, std::uint_fast32_t const poolSize, std::uint_fast16_t const blockSize) noexcept
Definition qf_mem.cpp:63
QMPoolSize m_blockSize
Definition qmpool.hpp:99
QMPoolSize getBlockSize() const noexcept
Definition qf_mem.cpp:286
void put(void *const block, std::uint_fast8_t const qsId) noexcept
Definition qf_mem.cpp:233
QP/C++ framework.
Definition qequeue.hpp:42
std::uint16_t QMPoolSize
Definition qmpool.hpp:50
std::uint16_t QMPoolCtr
Definition qmpool.hpp:60
#define QF_MEM_APP()
Definition qp.hpp:1322
#define Q_UNUSED_PAR(par_)
Helper macro to clearly mark unused parameters of functions.
Definition qp.hpp:498
#define QF_MEM_SYS()
Definition qp.hpp:1317
Internal (package scope) QP/C++ interface.
#define Q_PTR2UINT_CAST_(ptr_)
Internal helper macro to cast pointers to integers.
Definition qp_pkg.hpp:72
#define QF_PTR_RANGE_(x_, min_, max_)
Definition qp_pkg.hpp:73
Sample QP/C++ port.
#define QS_OBJ_PRE(obj_)
Definition qs_dummy.hpp:158
#define QS_TIME_PRE()
Definition qs_dummy.hpp:155
#define QS_MPC_PRE(ctr_)
Definition qs_dummy.hpp:161
#define QS_END_PRE()
Definition qs_dummy.hpp:150
#define QS_BEGIN_PRE(rec_, qsId_)
Definition qs_dummy.hpp:149
QS/C++ port to a 32-bit CPU, generic C++ compiler.
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