QP/C++  6.9.3
Real-Time Embedded Framework
qf_mem.cpp
Go to the documentation of this file.
1 
38 #define QP_IMPL // this is QP implementation
39 #include "qf_port.hpp" // QF port
40 #include "qf_pkg.hpp" // QF package-scope interface
41 #include "qassert.h" // QP embedded systems-friendly assertions
42 #ifdef Q_SPY // QS software tracing enabled?
43  #include "qs_port.hpp" // QS port
44  #include "qs_pkg.hpp" // QS facilities for pre-defined trace records
45 #else
46  #include "qs_dummy.hpp" // disable the QS software tracing
47 #endif // Q_SPY
48 
49 
50 namespace QP {
51 
52 Q_DEFINE_THIS_MODULE("qf_mem")
53 
54 //****************************************************************************
63 QMPool::QMPool(void)
64  : m_start(nullptr),
65  m_end(nullptr),
66  m_free_head(nullptr),
67  m_blockSize(0U),
68  m_nTot(0U),
69  m_nFree(0U),
70  m_nMin(0U)
71 {}
72 
73 //****************************************************************************
103 void QMPool::init(void * const poolSto, std::uint_fast32_t poolSize,
104  std::uint_fast16_t blockSize) noexcept
105 {
109  Q_REQUIRE_ID(100, (poolSto != nullptr)
110  && (poolSize >= sizeof(QFreeBlock))
111  && (static_cast<std::uint_fast16_t>(blockSize + sizeof(QFreeBlock))
112  > blockSize));
113 
114  m_free_head = poolSto;
115 
116  // round up the blockSize to fit an integer number of pointers...
117  //start with one
118  m_blockSize = static_cast<QMPoolSize>(sizeof(QFreeBlock));
119 
120  //# free blocks in a memory block
121  std::uint_fast16_t nblocks = 1U;
122  while (m_blockSize < static_cast<QMPoolSize>(blockSize)) {
123  m_blockSize += static_cast<QMPoolSize>(sizeof(QFreeBlock));
124  ++nblocks;
125  }
126  // use rounded-up value
127  blockSize = static_cast<std::uint_fast16_t>(m_blockSize);
128 
129  // the whole pool buffer must fit at least one rounded-up block
130  Q_ASSERT_ID(110, poolSize >= blockSize);
131 
132  // chain all blocks together in a free-list...
133 
134  // don't count the last block
135  poolSize -= static_cast<std::uint_fast32_t>(blockSize);
136  m_nTot = 1U; // one (the last) block in the pool
137 
138  // start at the head of the free list
139  QFreeBlock *fb = static_cast<QFreeBlock *>(m_free_head);
140 
141  // chain all blocks together in a free-list...
142  while (poolSize >= blockSize) {
143  fb->m_next = &QF_PTR_AT_(fb, nblocks); // setup the next link
144  fb = fb->m_next; // advance to next block
145  // reduce the available pool size
146  poolSize -= static_cast<std::uint_fast32_t>(blockSize);
147  ++m_nTot; // increment the number of blocks so far
148  }
149 
150  fb->m_next = nullptr; // the last link points to NULL
151  m_nFree = m_nTot; // all blocks are free
152  m_nMin = m_nTot; // the minimum number of free blocks
153  m_start = poolSto; // the original start this pool buffer
154  m_end = fb; // the last block in this pool
155 }
156 
157 //****************************************************************************
174 void QMPool::put(void * const b, std::uint_fast8_t const qs_id) noexcept {
175 
179  Q_REQUIRE_ID(200, (m_nFree < m_nTot)
180  && QF_PTR_RANGE_(b, m_start, m_end));
182 
183  QF_CRIT_E_();
184  static_cast<QFreeBlock*>(b)->m_next =
185  static_cast<QFreeBlock *>(m_free_head); // link into the free list
186  m_free_head = b; // set as new head of the free list
187  ++m_nFree; // one more free block in this pool
188 
190  QS_TIME_PRE_(); // timestamp
191  QS_OBJ_PRE_(this); // this memory pool
192  QS_MPC_PRE_(m_nFree); // the number of free blocks in the pool
194 
195  QF_CRIT_X_();
196  static_cast<void>(qs_id); // unused parameter, if Q_SPY not defined
197 }
198 
199 //****************************************************************************
224 void *QMPool::get(std::uint_fast16_t const margin,
225  std::uint_fast8_t const qs_id) noexcept
226 {
227  QFreeBlock *fb;
229 
230  QF_CRIT_E_();
231  // have the than margin?
232  if (m_nFree > static_cast<QMPoolCtr>(margin)) {
233  fb = static_cast<QFreeBlock *>(m_free_head); // get a free block
234 
235  // the pool has some free blocks, so a free block must be available
236  Q_ASSERT_CRIT_(310, fb != nullptr);
237 
238  // put volatile to a temporary to avoid UB
239  void * const fb_next = fb->m_next;
240 
241  // is the pool becoming empty?
242  --m_nFree; // one free block less
243  if (m_nFree == 0U) {
244  // pool is becoming empty, so the next free block must be NULL
245  Q_ASSERT_CRIT_(320, fb_next == nullptr);
246 
247  m_nMin = 0U;// remember that pool got empty
248  }
249  else {
250  // pool is not empty, so the next free block must be in range
251  //
252  // NOTE: the next free block pointer can fall out of range
253  // when the client code writes past the memory block, thus
254  // corrupting the next block.
255  Q_ASSERT_CRIT_(330, QF_PTR_RANGE_(fb_next, m_start, m_end));
256 
257  // is the number of free blocks the new minimum so far?
258  if (m_nMin > m_nFree) {
259  m_nMin = m_nFree; // remember the minimum so far
260  }
261  }
262 
263  m_free_head = fb_next; // set the head to the next free block
264 
266  QS_TIME_PRE_(); // timestamp
267  QS_OBJ_PRE_(this); // this memory pool
268  QS_MPC_PRE_(m_nFree); // the number of free blocks in the pool
269  QS_MPC_PRE_(m_nMin); // the mninimum # free blocks in the pool
271  }
272  // don't have enough free blocks at this point
273  else {
274  fb = nullptr;
275 
277  QS_TIME_PRE_(); // timestamp
278  QS_OBJ_PRE_(m_start); // the memory managed by this pool
279  QS_MPC_PRE_(m_nFree); // the # free blocks in the pool
280  QS_MPC_PRE_(margin); // the requested margin
282  }
283  QF_CRIT_X_();
284 
285  static_cast<void>(qs_id); // unused parameter, if Q_SPY not defined
286 
287  return fb; // return the block or NULL pointer to the caller
288 }
289 
290 //****************************************************************************
304 
307  && (1U <= poolId)
308  && (poolId <= QF_maxPool_));
310  QF_CRIT_E_();
311  std::uint_fast16_t const min = static_cast<std::uint_fast16_t>(
312  QF_pool_[poolId - 1U].m_nMin);
313  QF_CRIT_X_();
314 
315  return min;
316 }
317 
318 } // namespace QP
319 
unsigned int uint_fast16_t
Definition: 16bit/stdint.h:38
unsigned int uint_fast8_t
Definition: 16bit/stdint.h:36
unsigned long uint_fast32_t
Definition: 16bit/stdint.h:40
static std::uint_fast16_t getPoolMin(std::uint_fast8_t const poolId) noexcept
Definition: qf_mem.cpp:303
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:174
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:103
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:224
Definition: struct.dox:1
@ QS_QF_MPOOL_GET_ATTEMPT
attempt to get a memory block failed
Definition: qs.hpp:133
@ QS_QF_MPOOL_PUT
a memory block was returned to memory pool
Definition: qs.hpp:99
@ QS_QF_MPOOL_GET
a memory block was removed from memory pool
Definition: qs.hpp:98
std::uint8_t QMPoolCtr
Definition: qmpool.hpp:71
std::uint8_t QMPoolSize
Definition: qmpool.hpp:56
std::uint_fast8_t QF_maxPool_
Definition: qf_dyn.cpp:55
QFreeBlock *volatile m_next
link to the next free block
Definition: qf_pkg.hpp:123
QF_EPOOL_TYPE_ QF_pool_[QF_MAX_EPOOL]
allocate event pools
Definition: qf_dyn.cpp:54
Customizable and memory-efficient assertions for embedded systems.
#define Q_DEFINE_THIS_MODULE(name_)
Definition: qassert.h:120
#define Q_ASSERT_ID(id_, test_)
Definition: qassert.h:155
#define Q_REQUIRE_ID(id_, test_)
Definition: qassert.h:279
#define Q_DIM(array_)
Definition: qassert.h:337
Internal (package scope) QF/C++ interface.
#define QF_CRIT_STAT_
Definition: qf_pkg.hpp:56
#define QF_PTR_AT_(base_, i_)
access element at index i_ from the base pointer base_
Definition: qf_pkg.hpp:171
#define Q_ASSERT_CRIT_(id_, test_)
Definition: qf_pkg.hpp:94
#define QF_CRIT_X_()
Definition: qf_pkg.hpp:77
#define QF_PTR_RANGE_(x_, min_, max_)
Definition: qf_pkg.hpp:168
#define QF_CRIT_E_()
Definition: qf_pkg.hpp:66
#define QS_TIME_PRE_()
Definition: qs.hpp:266
Dummy definitions of the QS macros that avoid code generation from the QS instrumentation.
#define QS_BEGIN_NOCRIT_PRE_(rec_, qs_id_)
Definition: qs_dummy.hpp:98
#define QS_OBJ_PRE_(obj_)
Definition: qs_dummy.hpp:107
#define QS_MPC_PRE_(ctr_)
Definition: qs_dummy.hpp:110
#define QS_END_NOCRIT_PRE_()
Definition: qs_dummy.hpp:99
Internal (package scope) QS/C++ interface.
QS/C++ port to a 32-bit CPU, generic compiler.