QP/C  5.9.5
qf_mem.c
Go to the documentation of this file.
1 
40 #define QP_IMPL /* this is QP implementation */
41 #include "qf_port.h" /* QF port */
42 #include "qf_pkg.h" /* QF package-scope interface */
43 #include "qassert.h" /* QP embedded systems-friendly assertions */
44 #ifdef Q_SPY /* QS software tracing enabled? */
45  #include "qs_port.h" /* include QS port */
46 #else
47  #include "qs_dummy.h" /* disable the QS software tracing */
48 #endif /* Q_SPY */
49 
50 Q_DEFINE_THIS_MODULE("qf_mem")
51 
52 /****************************************************************************/
85 void QMPool_init(QMPool * const me, void * const poolSto,
86  uint_fast32_t poolSize, uint_fast16_t blockSize)
87 {
88  QFreeBlock *fb;
89  uint_fast16_t nblocks;
91 
96  Q_REQUIRE_ID(100, (poolSto != (void *)0)
97  && (poolSize >= (uint_fast32_t)sizeof(QFreeBlock))
98  && ((uint_fast16_t)(blockSize
99  + (uint_fast16_t)sizeof(QFreeBlock)) > blockSize));
100 
101  me->free_head = poolSto;
102 
103  /* round up the blockSize to fit an integer # free blocks, no division */
104  me->blockSize = (QMPoolSize)sizeof(QFreeBlock); /* start with just one */
105  nblocks = (uint_fast16_t)1;/* #free blocks that fit in one memory block */
106  while (me->blockSize < (QMPoolSize)blockSize) {
107  me->blockSize += (QMPoolSize)sizeof(QFreeBlock);
108  ++nblocks;
109  }
110  blockSize = (uint_fast16_t)me->blockSize; /* round-up to nearest block */
111 
112  /* the pool buffer must fit at least one rounded-up block */
113  Q_ASSERT_ID(110, poolSize >= (uint_fast32_t)blockSize);
114 
115  /* chain all blocks together in a free-list... */
116  poolSize -= (uint_fast32_t)blockSize; /* don't count the last block */
117  me->nTot = (QMPoolCtr)1; /* the last block already in the pool */
118  fb = (QFreeBlock *)me->free_head; /* start at the head of the free list */
119 
120  /* chain all blocks together in a free-list... */
121  while (poolSize >= (uint_fast32_t)blockSize) {
122  fb->next = &QF_PTR_AT_(fb, nblocks);/*point next link to next block */
123  fb = fb->next; /* advance to the next block */
124  poolSize -= (uint_fast32_t)blockSize; /* reduce available pool size */
125  ++me->nTot; /* increment the number of blocks so far */
126  }
127 
128  fb->next = (QFreeBlock *)0; /* the last link points to NULL */
129  me->nFree = me->nTot; /* all blocks are free */
130  me->nMin = me->nTot; /* the minimum number of free blocks */
131  me->start = poolSto; /* the original start this pool buffer */
132  me->end = fb; /* the last block in this pool */
133 
134  QS_BEGIN_(QS_QF_MPOOL_INIT, QS_priv_.locFilter[MP_OBJ], me->start)
135  QS_OBJ_(me->start); /* the memory managed by this pool */
136  QS_MPC_(me->nTot); /* the total number of blocks */
137  QS_END_()
138 }
139 
140 /****************************************************************************/
160 void QMPool_put(QMPool * const me, void *b) {
162 
166  Q_REQUIRE_ID(200, (me->nFree < me->nTot)
167  && QF_PTR_RANGE_(b, me->start, me->end));
168 
169  QF_CRIT_ENTRY_();
170  ((QFreeBlock *)b)->next = (QFreeBlock *)me->free_head;/* link into list */
171  me->free_head = b; /* set as new head of the free list */
172  ++me->nFree; /* one more free block in this pool */
173 
175  QS_TIME_(); /* timestamp */
176  QS_OBJ_(me->start); /* the memory managed by this pool */
177  QS_MPC_(me->nFree); /* the number of free blocks in the pool */
179 
180  QF_CRIT_EXIT_();
181 }
182 
183 /****************************************************************************/
210 void *QMPool_get(QMPool * const me, uint_fast16_t const margin) {
211  QFreeBlock *fb;
213 
214  QF_CRIT_ENTRY_();
215 
216  /* have more free blocks than the requested margin? */
217  if (me->nFree > (QMPoolCtr)margin) {
218  void *fb_next;
219  fb = (QFreeBlock *)me->free_head; /* get a free block */
220 
221  /* the pool has some free blocks, so a free block must be available */
222  Q_ASSERT_ID(310, fb != (QFreeBlock *)0);
223 
224  fb_next = fb->next; /* put volatile to a temporary to avoid UB */
225 
226  /* is the pool becoming empty? */
227  --me->nFree; /* one less free block */
228  if (me->nFree == (QMPoolCtr)0) {
229  /* pool is becoming empty, so the next free block must be NULL */
230  Q_ASSERT_ID(320, fb_next == (QFreeBlock *)0);
231 
232  me->nMin = (QMPoolCtr)0; /* remember that the pool got empty */
233  }
234  else {
235  /* pool is not empty, so the next free block must be in range
236  *
237  * NOTE: the next free block pointer can fall out of range
238  * when the client code writes past the memory block, thus
239  * corrupting the next block.
240  */
241  Q_ASSERT_ID(330, QF_PTR_RANGE_(fb_next, me->start, me->end));
242 
243  /* is the number of free blocks the new minimum so far? */
244  if (me->nMin > me->nFree) {
245  me->nMin = me->nFree; /* remember the new minimum */
246  }
247  }
248 
249  me->free_head = fb_next; /* set the head to the next free block */
250 
252  QS_priv_.locFilter[MP_OBJ], me->start)
253  QS_TIME_(); /* timestamp */
254  QS_OBJ_(me->start); /* the memory managed by this pool */
255  QS_MPC_(me->nFree); /* # of free blocks in the pool */
256  QS_MPC_(me->nMin); /* min # free blocks ever in the pool */
258 
259  }
260  /* don't have enough free blocks at this point */
261  else {
262  fb = (QFreeBlock *)0;
263 
265  QS_priv_.locFilter[MP_OBJ], me->start)
266  QS_TIME_(); /* timestamp */
267  QS_OBJ_(me->start); /* the memory managed by this pool */
268  QS_MPC_(me->nFree); /* the number of free blocks in the pool */
269  QS_MPC_(margin); /* the requested margin */
271  }
272  QF_CRIT_EXIT_();
273 
274  return fb; /* return the pointer to memory block or NULL to the caller */
275 }
276 
277 /****************************************************************************/
290  uint_fast16_t min;
292 
294  Q_REQUIRE_ID(400, ((uint_fast8_t)1 <= poolId)
295  && (poolId <= QF_maxPool_));
296 
297  QF_CRIT_ENTRY_();
298  min = (uint_fast16_t)QF_pool_[poolId - (uint_fast8_t)1].nMin;
299  QF_CRIT_EXIT_();
300 
301  return min;
302 }
#define QF_PTR_RANGE_(x_, min_, max_)
Definition: qf_pkg.h:124
a memory block was removed from memory pool
Definition: qs.h:95
#define QF_CRIT_ENTRY_()
This is an internal macro for entering a critical section.
Definition: qf_pkg.h:69
QMPoolCtr nTot
total number of blocks
Definition: qmpool.h:132
#define QF_CRIT_STAT_
This is an internal macro for defining the critical section status type.
Definition: qf_pkg.h:57
#define QS_BEGIN_NOCRIT_(rec_, objFilter_, obj_)
Internal macro to begin a QS record without entering critical section.
Definition: qs.h:686
QMPoolCtr nMin
minimum number of free blocks ever present in this pool
Definition: qmpool.h:144
#define Q_DEFINE_THIS_MODULE(name_)
Define the user-specified module name for assertions in this file.
Definition: qassert.h:101
event pool object
Definition: qs.h:1059
#define QS_END_()
Internal QS macro to end a QS record with exiting critical section.
Definition: qs.h:676
unsigned int uint_fast8_t
fast at-least 8-bit unsigned int
Definition: stdint.h:35
Internal (package scope) QF/C interface.
unsigned long uint_fast32_t
fast at-least 32-bit unsigned int
Definition: stdint.h:39
void * end
the last memory block managed by this memory pool
Definition: qmpool.h:126
void QMPool_put(QMPool *const me, void *b)
Recycles a memory block back to a memory pool.
Definition: qf_mem.c:160
#define Q_ASSERT_ID(id_, test_)
General purpose assertion with user-specified assertion-id.
Definition: qassert.h:136
QMPoolCtr volatile nFree
number of free blocks remaining
Definition: qmpool.h:135
attempt to get a memory block failed
Definition: qs.h:118
uint_fast16_t QF_getPoolMin(uint_fast8_t const poolId)
Obtain the minimum of free entries of the given event pool.
Definition: qf_mem.c:289
unsigned int uint_fast16_t
fast at-least 16-bit unsigned int
Definition: stdint.h:37
uint_fast8_t QF_maxPool_
of initialized event pools
Definition: qf_dyn.c:55
Customizable and memory-efficient assertions for embedded systems.
#define QS_BEGIN_(rec_, objFilter_, obj_)
Internal QS macro to begin a QS record with entering critical section.
Definition: qs.h:661
#define Q_REQUIRE_ID(id_, test_)
Assertion for checking preconditions with user-specified assertion-id.
Definition: qassert.h:254
void * QMPool_get(QMPool *const me, uint_fast16_t const margin)
Obtains a memory block from a memory pool.
Definition: qf_mem.c:210
#define QS_OBJ_(obj_)
Internal macro to output an unformatted object pointer data element.
Definition: qs.h:744
a memory pool was initialized
Definition: qs.h:94
#define QF_PTR_AT_(base_, i_)
access element at index i_ from the base pointer base_
Definition: qf_pkg.h:114
Native QF Memory Pool.
Definition: qmpool.h:118
a memory block was returned to memory pool
Definition: qs.h:96
structure representing a free block in the Native QF Memory Pool
Definition: qf_pkg.h:101
#define QS_TIME_()
Internal macro to output time stamp to a QS record.
Definition: qs.h:205
#define QS_END_NOCRIT_()
Internal QS macro to end a QS record without exiting critical section.
Definition: qs.h:700
void * start
the original start this pool
Definition: qmpool.h:123
QF_EPOOL_TYPE_ QF_pool_[QF_MAX_EPOOL]
allocate event pools
Definition: qf_dyn.c:54
void const * locFilter[MAX_OBJ]
local QS filters
Definition: qs.h:1069
#define QS_CRIT_STAT_
This is an internal macro for defining the critical section status type.
Definition: qs.h:592
void *volatile free_head
The head of the linked list of free blocks.
Definition: qmpool.h:120
void QMPool_init(QMPool *const me, void *const poolSto, uint_fast32_t poolSize, uint_fast16_t blockSize)
Initializes the native QF memory pool.
Definition: qf_mem.c:85
#define QF_CRIT_EXIT_()
This is an internal macro for exiting a critical section.
Definition: qf_pkg.h:81