QP/C++  8.0.2
Real-Time Embedded Framework
Loading...
Searching...
No Matches
qf_mem.cpp
Go to the documentation of this file.
1//============================================================================
2// QP/C++ Real-Time Embedded Framework (RTEF)
3// Version 8.0.2
4//
5// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
6//
7// Q u a n t u m L e a P s
8// ------------------------
9// Modern Embedded Software
10//
11// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
12//
13// This software is dual-licensed under the terms of the open-source GNU
14// General Public License (GPL) or under the terms of one of the closed-
15// source Quantum Leaps commercial licenses.
16//
17// Redistributions in source code must retain this top-level comment block.
18// Plagiarizing this software to sidestep the license obligations is illegal.
19//
20// NOTE:
21// The GPL does NOT permit the incorporation of this code into proprietary
22// programs. Please contact Quantum Leaps for commercial licensing options,
23// which expressly supersede the GPL and are designed explicitly for
24// closed-source distribution.
25//
26// Quantum Leaps contact information:
27// <www.state-machine.com/licensing>
28// <info@state-machine.com>
29//============================================================================
30#define QP_IMPL // this is QP implementation
31#include "qp_port.hpp" // QP port
32#include "qp_pkg.hpp" // QP package-scope interface
33#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
34#ifdef Q_SPY // QS software tracing enabled?
35 #include "qs_port.hpp" // QS port
36 #include "qs_pkg.hpp" // QS package-scope internal interface
37#else
38 #include "qs_dummy.hpp" // disable the QS software tracing
39#endif // Q_SPY
40
41// unnamed namespace for local definitions with internal linkage
42namespace {
43Q_DEFINE_THIS_MODULE("qf_mem")
44} // unnamed namespace
45
46namespace QP {
47
48//............................................................................
50 void * const poolSto,
51 std::uint_fast32_t const poolSize,
52 std::uint_fast16_t const blockSize) noexcept
53{
56
57 Q_REQUIRE_INCRIT(100, poolSto != nullptr);
58
59 m_freeHead = static_cast<void * *>(poolSto);
60
61 // find # free links in a memory block, see NOTE1
62 m_blockSize = static_cast<QMPoolSize>(2U * sizeof(void *));
63 std::uint_fast16_t inext = 2U;
64 while (m_blockSize < static_cast<QMPoolSize>(blockSize)) {
65 m_blockSize += static_cast<QMPoolSize>(sizeof(void *));
66 ++inext;
67 }
68
69 // the pool buffer must fit at least one rounded-up block
70 Q_ASSERT_INCRIT(110, poolSize >= m_blockSize);
71
72 // start at the head of the free list
73 void * *pfb = m_freeHead; // pointer to free block
74 std::uint32_t nTot = 1U; // the last block already in the list
75
76 // chain all blocks together in a free-list...
77 for (std::uint_fast32_t size = poolSize - m_blockSize;
78 size >= static_cast<std::uint_fast32_t>(m_blockSize);
79 size -= static_cast<std::uint_fast32_t>(m_blockSize))
80 {
81 pfb[0] = &pfb[inext]; // set the next link to next free block
82 pfb = static_cast<void * *>(pfb[0]); // advance to the next block
83 ++nTot; // one more free block in the pool
84 }
85 pfb[0] = nullptr; // the last link points to NULL
86
87 // dynamic range check
88#if (QF_MPOOL_CTR_SIZE == 1U)
89 Q_ASSERT_INCRIT(190, nTot < 0xFFU);
90#elif (QF_MPOOL_CTR_SIZE == 2U)
91 Q_ASSERT_INCRIT(190, nTot < 0xFFFFU);
92#endif
93
94 m_nTot = static_cast<QMPoolCtr>(nTot);
95 m_nFree = m_nTot; // all blocks are free
96 m_start = static_cast<void * *>(poolSto); // original start
97 m_end = pfb; // the last block in this pool
98 m_nMin = m_nTot; // the minimum # free blocks
99
100 QF_CRIT_EXIT();
101}
102
103//............................................................................
105 std::uint_fast16_t const margin,
106 std::uint_fast8_t const qsId) noexcept
107{
108#ifndef Q_SPY
109 Q_UNUSED_PAR(qsId);
110#endif
111
114
115 // get volatile into temporaries
116 void * *pfb = m_freeHead; // pointer to free block
117 QMPoolCtr nFree = m_nFree;
118
119 // have more free blocks than the requested margin?
120 if (nFree > static_cast<QMPoolCtr>(margin)) {
121 Q_ASSERT_INCRIT(310, pfb != nullptr);
122
123 // fast temporary
124 void * * const pfb_next = static_cast<void * *>(pfb[0]);
125
126 --nFree; // one less free block
127 if (nFree == 0U) { // is the pool becoming empty?
128 // pool is becoming empty, so the next free block must be NULL
129 Q_ASSERT_INCRIT(320, pfb_next == nullptr);
130
131 m_nFree = 0U; // no more free blocks
132 m_nMin = 0U; // remember that the pool got empty
133 }
134 else { // the pool is NOT empty
135
136 // the next free-block pointer must be in range
137 Q_ASSERT_INCRIT(330, QF_PTR_RANGE_(pfb_next, m_start, m_end));
138
139 m_nFree = nFree; // update the original
140 if (m_nMin > nFree) { // is this the new minimum?
141 m_nMin = nFree; // remember the minimum so far
142 }
143 }
144
145 m_freeHead = pfb_next; // set the head to the next free block
146
147 // change the allocated block contents so that it is different
148 // than a free block inside the pool.
149 pfb[0] = &m_end[1]; // invalid location beyond the end
150
151 QS_BEGIN_PRE(QS_QF_MPOOL_GET, qsId)
152 QS_TIME_PRE(); // timestamp
153 QS_OBJ_PRE(this); // this memory pool
154 QS_MPC_PRE(nFree); // # free blocks in the pool
155 QS_MPC_PRE(m_nMin); // min # free blocks ever in the pool
156 QS_END_PRE()
157 }
158 else { // don't have enough free blocks at this point
159 pfb = nullptr;
160
161 QS_BEGIN_PRE(QS_QF_MPOOL_GET_ATTEMPT, qsId)
162 QS_TIME_PRE(); // timestamp
163 QS_OBJ_PRE(this); // this memory pool
164 QS_MPC_PRE(nFree); // # free blocks in the pool
165 QS_MPC_PRE(margin); // the requested margin
166 QS_END_PRE()
167 }
168
169 QF_CRIT_EXIT();
170
171 return pfb; // return the block or nullptr to the caller
172}
173
174//............................................................................
176 void * const block,
177 std::uint_fast8_t const qsId) noexcept
178{
179#ifndef Q_SPY
180 Q_UNUSED_PAR(qsId);
181#endif
182
183 void * * const pfb = static_cast<void * *>(block); // pointer to free block
184
187
188 // get volatile into temporaries
189 void * * const freeHead = m_freeHead;
190 QMPoolCtr nFree = m_nFree;
191
192 Q_REQUIRE_INCRIT(400, nFree < m_nTot);
194
195 ++nFree; // one more free block in this pool
196
197 m_freeHead = pfb; // set as new head of the free list
198 m_nFree = nFree;
199 pfb[0] = freeHead; // link into the list
200
201 QS_BEGIN_PRE(QS_QF_MPOOL_PUT, qsId)
202 QS_TIME_PRE(); // timestamp
203 QS_OBJ_PRE(this); // this memory pool
204 QS_MPC_PRE(nFree); // the # free blocks in the pool
205 QS_END_PRE()
206
207 QF_CRIT_EXIT();
208}
209
210} // namespace QP
211
212//============================================================================
213// NOTE1:
214// The memory buffer for the pool is organized as an array of void* pointers
215// (see void * data type). These pointers are used to form a linked-list
216// of free blocks in the pool. The first location pfb[0] is the actual link.
217// The second location pfb[1] is used in SafeQP as the redundant "duplicate
218// storage" for the link at pfb[0]. Even though the "duplicate storage" is NOT
219// used in this QP edition, the minimum number of number of void* pointers
220// (void * data type) inside a memory block is still kept at 2 to maintain
221// the same policy for sizing the memory blocks.
void * get(std::uint_fast16_t const margin, std::uint_fast8_t const qsId) noexcept
Definition qf_mem.cpp:104
QMPoolCtr volatile m_nFree
Definition qmpool.hpp:76
void init(void *const poolSto, std::uint_fast32_t const poolSize, std::uint_fast16_t const blockSize) noexcept
Definition qf_mem.cpp:49
QMPoolSize m_blockSize
Definition qmpool.hpp:74
void **volatile m_freeHead
Definition qmpool.hpp:73
void put(void *const block, std::uint_fast8_t const qsId) noexcept
Definition qf_mem.cpp:175
QMPoolCtr m_nMin
Definition qmpool.hpp:77
void ** m_end
Definition qmpool.hpp:72
void ** m_start
Definition qmpool.hpp:71
QMPoolCtr m_nTot
Definition qmpool.hpp:75
QP/C++ framework.
std::uint16_t QMPoolSize
Definition qmpool.hpp:51
std::uint16_t QMPoolCtr
Definition qmpool.hpp:61
#define Q_UNUSED_PAR(par_)
Helper macro to clearly mark unused parameters of functions.
Definition qp.hpp:98
Internal (package scope) QP/C++ interface.
#define QF_PTR_RANGE_(x_, min_, max_)
Definition qp_pkg.hpp:36
Sample QP/C++ port.
#define QF_CRIT_ENTRY()
Definition qp_port.hpp:63
#define QF_CRIT_EXIT()
Definition qp_port.hpp:71
#define QF_CRIT_STAT
Definition qp_port.hpp:54
#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.
#define Q_ASSERT_INCRIT(id_, expr_)
Definition qsafe.h:50
#define Q_REQUIRE_INCRIT(id_, expr_)
Definition qsafe.h:87