/** * \description * The function allocates a memory block from the pool and returns a pointer * to the block back to the caller. * * \arguments * \arg[in,out] \c me pointer (see \ref derivation) * \arg[in] \c margin the minimum number of unused blocks still available * in the pool after the allocation. * * \note This function can be called from any task level or ISR level. * * \note The memory pool \a me must be initialized before any events can * be requested from it. Also, the QMPool_get() function uses internally a * QF critical section, so you should be careful not to call it from within * a critical section when nesting of critical section is not supported. * * \attention * An allocated block must be later returned back to the same pool * from which it has been allocated. * * \sa QMPool_put() */ void *QMPool_get(QMPool * const me, uint_fast16_t const margin) { QFreeBlock *fb; QF_CRIT_STAT_ QF_CRIT_ENTRY_(); /* have more free blocks than the requested margin? */ if (me->nFree > (QMPoolCtr)margin) { void *fb_next; fb = (QFreeBlock *)me->free_head; /* get a free block */ /* the pool has some free blocks, so a free block must be available */ Q_ASSERT_ID(110, fb != (QFreeBlock *)0); fb_next = fb->next; /* put volatile to a temporary to avoid UB */ /* is the pool becoming empty? */ --me->nFree; /* one less free block */ if (me->nFree == (QMPoolCtr)0) { /* pool is becoming empty, so the next free block must be NULL */ Q_ASSERT_ID(120, fb_next == (QFreeBlock *)0); me->nMin = (QMPoolCtr)0; /* remember that the pool got empty */ } else { /* pool is not empty, so the next free block must be in range * * NOTE: the next free block pointer can fall out of range * when the client code writes past the memory block, thus * corrupting the next block. */ Q_ASSERT_ID(130, QF_PTR_RANGE_(fb_next, me->start, me->end)); /* is the number of free blocks the new minimum so far? */ if (me->nMin > me->nFree) { me->nMin = me->nFree; /* remember the new minimum */ } } me->free_head = fb_next; /* set the head to the next free block */ QS_BEGIN_NOCRIT_(QS_QF_MPOOL_GET, QS_priv_.mpObjFilter, me->start) QS_TIME_(); /* timestamp */ QS_OBJ_(me->start); /* the memory managed by this pool */ QS_MPC_(me->nFree); /* # of free blocks in the pool */ QS_MPC_(me->nMin); /* min # free blocks ever in the pool */ QS_END_NOCRIT_() }
/*..........................................................................*/ void QMPool_put(QMPool *me, void *b) { QF_CRIT_STAT_ Q_REQUIRE(me->nFree <= me->nTot); /* # free blocks must be < total */ Q_REQUIRE(QF_PTR_RANGE_(b, me->start, me->end)); /* b must be in range */ QF_CRIT_ENTRY_(); ((QFreeBlock *)b)->next = (QFreeBlock *)me->free_head;/* link into list */ me->free_head = b; /* set as new head of the free list */ ++me->nFree; /* one more free block in this pool */ QS_BEGIN_NOCRIT_(QS_QF_MPOOL_PUT, QS_mpObj_, me->start) QS_TIME_(); /* timestamp */ QS_OBJ_(me->start); /* the memory managed by this pool */ QS_MPC_(me->nFree); /* the number of free blocks in the pool */ QS_END_NOCRIT_() QF_CRIT_EXIT_(); }