QP/C++  7.4.0-rc.1
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 6.1.1 <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) : qpcpp
13// Support ends : 2024-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.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
43#define QP_IMPL // this is QP implementation
44#include "qp_port.hpp" // QP port
45#include "qp_pkg.hpp" // 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.hpp" // QS port
49 #include "qs_pkg.hpp" // QS facilities for pre-defined trace records
50#else
51 #include "qs_dummy.hpp" // disable the QS software tracing
52#endif // Q_SPY
53
54// unnamed namespace for local definitions with internal linkage
55namespace {
56Q_DEFINE_THIS_MODULE("qf_mem")
57} // unnamed namespace
58
59//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
60// Check for the minimum required QP version
61#if (QP_VERSION < 730U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U))
62#error qpcpp version 7.3.0 or higher required
63#endif
64//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
65
66//$define${QF::QMPool} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
67namespace QP {
68
69//${QF::QMPool} ..............................................................
70
71//${QF::QMPool::init} ........................................................
73 void * const poolSto,
74 std::uint_fast32_t const poolSize,
75 std::uint_fast16_t const blockSize) noexcept
76{
79 QF_MEM_SYS();
80
81 Q_REQUIRE_INCRIT(100, (poolSto != nullptr)
82 && (poolSize >= static_cast<std::uint_fast32_t>(sizeof(QFreeBlock)))
83 && (static_cast<std::uint_fast16_t>(blockSize + sizeof(QFreeBlock))
84 > blockSize));
85
86 m_free_head = static_cast<QFreeBlock *>(poolSto);
87
88 // find # free blocks in a memory block, NO DIVISION
89 m_blockSize = static_cast<QMPoolSize>(sizeof(QFreeBlock));
90 std::uint_fast16_t nblocks = 1U;
91 while (m_blockSize < static_cast<QMPoolSize>(blockSize)) {
92 m_blockSize += static_cast<QMPoolSize>(sizeof(QFreeBlock));
93 ++nblocks;
94 }
95
96 // the pool buffer must fit at least one rounded-up block
97 Q_ASSERT_INCRIT(110, poolSize >= m_blockSize);
98
99 // start at the head of the free list
100 QFreeBlock *fb = m_free_head;
101 std::uint32_t nTot = 1U; // the last block already in the list
102
103 // chain all blocks together in a free-list...
104 for (std::uint_fast32_t size = poolSize - m_blockSize;
105 size >= static_cast<std::uint_fast32_t>(m_blockSize);
106 size -= static_cast<std::uint_fast32_t>(m_blockSize))
107 {
108 fb->m_next = &fb[nblocks]; // point next link to next block
109 #ifndef Q_UNSAFE
110 fb->m_next_dis = ~Q_UINTPTR_CAST_(fb->m_next);
111 #endif
112 fb = fb->m_next; // advance to the next block
113 ++nTot; // one more free block in the pool
114 }
115
116 // dynamic range check
117 #if (QF_MPOOL_CTR_SIZE == 1U)
118 Q_ENSURE_INCRIT(190, nTot < 0xFFU);
119 #elif (QF_MPOOL_CTR_SIZE == 2U)
120 Q_ENSURE_INCRIT(190, nTot < 0xFFFFU);
121 #endif
122
123 fb->m_next = nullptr; // the last link points to NULL
124 #ifndef Q_UNSAFE
125 fb->m_next_dis = ~Q_UINTPTR_CAST_(fb->m_next);
126 #endif
127
128 m_nTot = static_cast<QMPoolCtr>(nTot);
129 m_nFree = m_nTot; // all blocks are free
130 m_nMin = m_nTot; // the minimum # free blocks
131 m_start = static_cast<QFreeBlock *>(poolSto); // original start
132 m_end = fb; // the last block in this pool
133
134 QF_MEM_APP();
135 QF_CRIT_EXIT();
136}
137
138//${QF::QMPool::get} .........................................................
140 std::uint_fast16_t const margin,
141 std::uint_fast8_t const qsId) noexcept
142{
143 #ifndef Q_SPY
144 Q_UNUSED_PAR(qsId);
145 #endif
146
149 QF_MEM_SYS();
150
151 // have more free blocks than the requested margin?
152 QFreeBlock *fb;
153 if (m_nFree > static_cast<QMPoolCtr>(margin)) {
154 fb = m_free_head; // get a free block
155
156 // a free block must be valid
157 Q_ASSERT_INCRIT(300, fb != nullptr);
158
159 QFreeBlock * const fb_next = fb->m_next;
160
161 // the free block must have integrity (duplicate inverse storage)
163 == static_cast<std::uintptr_t>(~fb->m_next_dis));
164
165 m_nFree = (m_nFree - 1U); // one free block less
166 if (m_nFree == 0U) { // is the pool becoming empty?
167 // pool is becoming empty, so the next free block must be NULL
168 Q_ASSERT_INCRIT(320, fb_next == nullptr);
169
170 m_nMin = 0U; // remember that the pool got empty
171 }
172 else {
173 // invariant:
174 // The pool is not empty, so the next free-block pointer,
175 // so the next free block must be in range.
176
177 // NOTE: The next free block pointer can fall out of range
178 // when the client code writes past the memory block, thus
179 // corrupting the next block.
180 Q_ASSERT_INCRIT(330,
181 QF_PTR_RANGE_(fb_next, m_start, m_end));
182
183 // is the # free blocks the new minimum so far?
184 if (m_nMin > m_nFree) {
185 m_nMin = m_nFree; // remember the minimum so far
186 }
187 }
188
189 m_free_head = fb_next; // set the head to the next free block
190
191 QS_BEGIN_PRE_(QS_QF_MPOOL_GET, qsId)
192 QS_TIME_PRE_(); // timestamp
193 QS_OBJ_PRE_(this); // this memory pool
194 QS_MPC_PRE_(m_nFree); // # of free blocks in the pool
195 QS_MPC_PRE_(m_nMin); // min # free blocks ever in the pool
196 QS_END_PRE_()
197 }
198 else { // don't have enough free blocks at this point
199 fb = nullptr;
200
201 QS_BEGIN_PRE_(QS_QF_MPOOL_GET_ATTEMPT, qsId)
202 QS_TIME_PRE_(); // timestamp
203 QS_OBJ_PRE_(this); // this memory pool
204 QS_MPC_PRE_(m_nFree); // # of free blocks in the pool
205 QS_MPC_PRE_(margin); // the requested margin
206 QS_END_PRE_()
207 }
208
209 QF_MEM_APP();
210 QF_CRIT_EXIT();
211
212 return fb; // return the block or nullptr to the caller
213}
214
215//${QF::QMPool::put} .........................................................
217 void * const block,
218 std::uint_fast8_t const qsId) noexcept
219{
220 #ifndef Q_SPY
221 Q_UNUSED_PAR(qsId);
222 #endif
223
224 QFreeBlock * const fb = static_cast<QFreeBlock *>(block);
225
228 QF_MEM_SYS();
229
230 Q_REQUIRE_INCRIT(200, (m_nFree < m_nTot)
231 && QF_PTR_RANGE_(fb, m_start, m_end));
232
233 fb->m_next = m_free_head; // link into list
234 #ifndef Q_UNSAFE
235 fb->m_next_dis = static_cast<std::uintptr_t>(
236 ~Q_UINTPTR_CAST_(fb->m_next));
237 #endif
238
239 // set as new head of the free list
240 m_free_head = fb;
241
242 m_nFree = m_nFree + 1U; // one more free block in this pool
243
244 QS_BEGIN_PRE_(QS_QF_MPOOL_PUT, qsId)
245 QS_TIME_PRE_(); // timestamp
246 QS_OBJ_PRE_(this); // this memory pool
247 QS_MPC_PRE_(m_nFree); // the # free blocks in the pool
248 QS_END_PRE_()
249
250 QF_MEM_APP();
251 QF_CRIT_EXIT();
252}
253
254//${QF::QMPool::getBlockSize} ................................................
256 return m_blockSize;
257}
258
259} // namespace QP
260//$enddef${QF::QMPool} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Structure representing a free block in QP::QMPool.
Definition qmpool.hpp:84
QFreeBlock * m_next
Definition qmpool.hpp:86
std::uintptr_t m_next_dis
Definition qmpool.hpp:89
void * get(std::uint_fast16_t const margin, std::uint_fast8_t const qsId) noexcept
Definition qf_mem.cpp:139
void init(void *const poolSto, std::uint_fast32_t const poolSize, std::uint_fast16_t const blockSize) noexcept
Definition qf_mem.cpp:72
QMPoolSize m_blockSize
Definition qmpool.hpp:106
QMPoolSize getBlockSize() const noexcept
Definition qf_mem.cpp:255
void put(void *const block, std::uint_fast8_t const qsId) noexcept
Definition qf_mem.cpp:216
QP/C++ framework.
Definition qequeue.hpp:50
std::uint16_t QMPoolSize
Definition qmpool.hpp:58
std::uint16_t QMPoolCtr
Definition qmpool.hpp:68
@ QS_QF_MPOOL_GET
a memory block was removed from memory pool
Definition qs.hpp:105
@ QS_QF_MPOOL_GET_ATTEMPT
attempt to get a memory block failed
Definition qs.hpp:140
@ QS_QF_MPOOL_PUT
a memory block was returned to memory pool
Definition qs.hpp:106
#define QF_MEM_APP()
Definition qp.hpp:1331
#define Q_UNUSED_PAR(par_)
Definition qp.hpp:539
#define QF_MEM_SYS()
Definition qp.hpp:1326
Internal (package scope) QP/C++ interface.
#define Q_UINTPTR_CAST_(ptr_)
Internal helper macro to cast pointers to integers.
Definition qp_pkg.hpp:81
#define QF_PTR_RANGE_(x_, min_, max_)
Definition qp_pkg.hpp:80
Sample QP/C++ port.
#define QS_TIME_PRE_()
Definition qs.hpp:473
QS/C++ package-scope interface.
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