QP/C++  7.0.1
Real-Time Embedded Framework
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 5.2.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 : 2023-12-31
14// License scope:
15//
16// Copyright (C) 2005 Quantum Leaps, LLC <state-machine.com>.
17//
18// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
19//
20// This software is dual-licensed under the terms of the open source GNU
21// General Public License version 3 (or any later version), or alternatively,
22// under the terms of one of the closed source Quantum Leaps commercial
23// licenses.
24//
25// The terms of the open source GNU General Public License version 3
26// can be found at: <www.gnu.org/licenses/gpl-3.0>
27//
28// The terms of the closed source Quantum Leaps commercial licenses
29// can be found at: <www.state-machine.com/licensing>
30//
31// Redistributions in source code must retain this top-level comment block.
32// Plagiarizing this software to sidestep the license obligations is illegal.
33//
34// Contact information:
35// <www.state-machine.com/licensing>
36// <info@state-machine.com>
37//
38//$endhead${src::qf::qf_mem.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
44
45#define QP_IMPL // this is QP implementation
46#include "qf_port.hpp" // QF port
47#include "qf_pkg.hpp" // QF package-scope interface
48#include "qassert.h" // QP embedded systems-friendly assertions
49#ifdef Q_SPY // QS software tracing enabled?
50 #include "qs_port.hpp" // QS port
51 #include "qs_pkg.hpp" // QS facilities for pre-defined trace records
52#else
53 #include "qs_dummy.hpp" // disable the QS software tracing
54#endif // Q_SPY
55
56// unnamed namespace for local definitions with internal linkage
57namespace {
59} // unnamed namespace
60
61//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
62// Check for the minimum required QP version
63#if (QP_VERSION < 690U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U))
64#error qpcpp version 6.9.0 or higher required
65#endif
66//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
67
68//$define${QF::QMPool} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
69namespace QP {
70
71//${QF::QMPool} ..............................................................
72
73//${QF::QMPool::QMPool} ......................................................
75 : m_start(nullptr),
76 m_end(nullptr),
77 m_free_head(nullptr),
78 m_blockSize(0U),
79 m_nTot(0U),
80 m_nFree(0U),
81 m_nMin(0U)
82{}
83
84//${QF::QMPool::init} ........................................................
86 void * const poolSto,
87 std::uint_fast32_t poolSize,
88 std::uint_fast16_t blockSize) noexcept
89{
93 Q_REQUIRE_ID(100, (poolSto != nullptr)
94 && (poolSize >= static_cast<std::uint_fast32_t>(sizeof(QFreeBlock)))
95 && (static_cast<std::uint_fast16_t>(blockSize + sizeof(QFreeBlock))
96 > blockSize));
97
98 m_free_head = poolSto;
99
100 // round up the blockSize to fit an integer number of pointers...
101 //start with one
102 m_blockSize = static_cast<QMPoolSize>(sizeof(QFreeBlock));
103
104 //# free blocks in a memory block
105 std::uint_fast16_t nblocks = 1U;
106 while (m_blockSize < static_cast<QMPoolSize>(blockSize)) {
107 m_blockSize += static_cast<QMPoolSize>(sizeof(QFreeBlock));
108 ++nblocks;
109 }
110 // use rounded-up value
111 blockSize = static_cast<std::uint_fast16_t>(m_blockSize);
112
113 // the whole pool buffer must fit at least one rounded-up block
114 Q_ASSERT_ID(110, poolSize >= blockSize);
115
116 // chain all blocks together in a free-list...
117
118 // don't count the last block
119 poolSize -= static_cast<std::uint_fast32_t>(blockSize);
120 m_nTot = 1U; // one (the last) block in the pool
121
122 // start at the head of the free list
123 QFreeBlock *fb = static_cast<QFreeBlock *>(m_free_head);
124
125 // chain all blocks together in a free-list...
126 while (poolSize >= blockSize) {
127 fb->m_next = &fb[nblocks]; // setup the next link
128 fb = fb->m_next; // advance to next block
129 // reduce the available pool size
130 poolSize -= static_cast<std::uint_fast32_t>(blockSize);
131 ++m_nTot; // increment the number of blocks so far
132 }
133
134 fb->m_next = nullptr; // the last link points to NULL
135 m_nFree = m_nTot; // all blocks are free
136 m_nMin = m_nTot; // the minimum number of free blocks
137 m_start = poolSto; // the original start this pool buffer
138 m_end = fb; // the last block in this pool
139}
140
141//${QF::QMPool::get} .........................................................
143 std::uint_fast16_t const margin,
144 std::uint_fast8_t const qs_id) noexcept
145{
146 Q_UNUSED_PAR(qs_id); // when Q_SPY not defined
147
149 QF_CRIT_E_();
150
151 // have the than margin?
152 QFreeBlock *fb;
153 if (m_nFree > static_cast<QMPoolCtr>(margin)) {
154 fb = static_cast<QFreeBlock *>(m_free_head); // get a free block
155
156 // the pool has some free blocks, so a free block must be available
157 Q_ASSERT_CRIT_(310, fb != nullptr);
158
159 // put volatile to a temporary to avoid UB
160 void * const fb_next = fb->m_next;
161
162 // is the pool becoming empty?
163 m_nFree = (m_nFree - 1U); // one free block less
164 if (m_nFree == 0U) {
165 // pool is becoming empty, so the next free block must be NULL
166 Q_ASSERT_CRIT_(320, fb_next == nullptr);
167
168 m_nMin = 0U;// remember that pool got empty
169 }
170 else {
171 // pool is not empty, 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_CRIT_(330, QF_PTR_RANGE_(fb_next, m_start, m_end));
177
178 // is the number of free blocks the new minimum so far?
179 if (m_nMin > m_nFree) {
180 m_nMin = m_nFree; // remember the minimum so far
181 }
182 }
183
184 m_free_head = fb_next; // set the head to the next free block
185
187 QS_TIME_PRE_(); // timestamp
188 QS_OBJ_PRE_(this); // this memory pool
189 QS_MPC_PRE_(m_nFree); // # of free blocks in the pool
190 QS_MPC_PRE_(m_nMin); // min # free blocks ever in the pool
192 }
193 // don't have enough free blocks at this point
194 else {
195 fb = nullptr;
196
198 QS_TIME_PRE_(); // timestamp
199 QS_OBJ_PRE_(m_start); // the memory managed by this pool
200 QS_MPC_PRE_(m_nFree); // the # free blocks in the pool
201 QS_MPC_PRE_(margin); // the requested margin
203 }
204 QF_CRIT_X_();
205
206 return fb; // return the block or NULL pointer to the caller
207
208}
209
210//${QF::QMPool::put} .........................................................
212 void * const b,
213 std::uint_fast8_t const qs_id) noexcept
214{
215 Q_UNUSED_PAR(qs_id); // when Q_SPY not defined
216
220 Q_REQUIRE_ID(200, (m_nFree < m_nTot)
221 && QF_PTR_RANGE_(b, m_start, m_end));
223 QF_CRIT_E_();
224 static_cast<QFreeBlock*>(b)->m_next =
225 static_cast<QFreeBlock *>(m_free_head); // link into the free list
226 m_free_head = b; // set as new head of the free list
227 m_nFree = (m_nFree + 1U); // one more free block in this pool
228
230 QS_TIME_PRE_(); // timestamp
231 QS_OBJ_PRE_(this); // this memory pool
232 QS_MPC_PRE_(m_nFree); // the number of free blocks in the pool
234
235 QF_CRIT_X_();
236}
237
238//${QF::QMPool::getBlockSize} ................................................
240 return m_blockSize;
241}
242
243} // namespace QP
244//$enddef${QF::QMPool} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
void put(void *const b, std::uint_fast8_t const qs_id) noexcept
Returns a memory block back to a memory pool.
Definition: qf_mem.cpp:211
void init(void *const poolSto, std::uint_fast32_t poolSize, std::uint_fast16_t blockSize) noexcept
Initializes the native QF event pool.
Definition: qf_mem.cpp:85
QMPoolSize m_blockSize
maximum block size (in bytes)
Definition: qmpool.hpp:140
void * get(std::uint_fast16_t const margin, std::uint_fast8_t const qs_id) noexcept
Obtains a memory block from a memory pool.
Definition: qf_mem.cpp:142
QMPool()
public default constructor
Definition: qf_mem.cpp:74
QMPoolSize getBlockSize() const noexcept
return the fixed block-size of the blocks managed by this pool
Definition: qf_mem.cpp:239
QP/C++ framework.
Definition: exa_native.dox:1
std::uint16_t QMPoolSize
The data type to store the block-size based on the macro QF_MPOOL_SIZ_SIZE.
Definition: qmpool.hpp:76
std::uint16_t QMPoolCtr
The data type to store the block-counter based on the macro QF_MPOOL_CTR_SIZE.
Definition: qmpool.hpp:92
@ QS_QF_MPOOL_GET_ATTEMPT
attempt to get a memory block failed
Definition: qs.hpp:202
@ QS_QF_MPOOL_PUT
a memory block was returned to memory pool
Definition: qs.hpp:168
@ QS_QF_MPOOL_GET
a memory block was removed from memory pool
Definition: qs.hpp:167
QFreeBlock *volatile m_next
link to the next free block
Definition: qf_pkg.hpp:97
Structure representing a free block in the Native QF Memory Pool.
Definition: qf_pkg.hpp:96
Customizable and memory-efficient Design by Contract (DbC) for embedded systems.
#define Q_DEFINE_THIS_MODULE(name_)
Definition: qassert.h:141
#define Q_REQUIRE_ID(id_, expr_)
Definition: qassert.h:243
#define Q_ASSERT_ID(id_, expr_)
Definition: qassert.h:170
#define Q_UNUSED_PAR(par_)
Helper macro to clearly mark unused parameters of functions.
Definition: qep.hpp:965
Internal (package scope) QF/C++ interface.
#define QF_CRIT_STAT_
This is an internal macro for defining the critical section status type.
Definition: qf_pkg.hpp:147
#define Q_ASSERT_CRIT_(id_, test_)
Definition: qf_pkg.hpp:187
#define QF_CRIT_X_()
This is an internal macro for exiting a critical section.
Definition: qf_pkg.hpp:170
#define QF_PTR_RANGE_(x_, min_, max_)
helper macro to test that a pointer x_ is in range between min_ and max_
Definition: qf_pkg.hpp:212
#define QF_CRIT_E_()
This is an internal macro for entering a critical section.
Definition: qf_pkg.hpp:158
#define QS_TIME_PRE_()
Output time stamp to a QS record (used in predefined and application-specific trace records)
Definition: qs.hpp:1082
Internal (package scope) QS/C++ interface.
#define QS_BEGIN_NOCRIT_PRE_(rec_, qs_id_)
Internal QS macro to begin a predefined QS record without critical section.
Definition: qs_pkg.hpp:144
#define QS_OBJ_PRE_(obj_)
Internal QS macro to output object pointer data element.
Definition: qs_pkg.hpp:193
#define QS_MPC_PRE_(ctr_)
Definition: qs_pkg.hpp:277
#define QS_END_NOCRIT_PRE_()
Internal QS macro to end a predefiend QS record without critical section.
Definition: qs_pkg.hpp:153