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