Пример #1
0
/**
* \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_()

    }
Пример #2
0
/*..........................................................................*/
void QMPool_init(QMPool * const me, void * const poolSto,
                 uint32_t poolSize, QMPoolSize blockSize)
{
    QFreeBlock *fb;
    uint32_t nblocks;
    QS_CRIT_STAT_

    /* The memory block must be valid
    * and the poolSize must fit at least one free block
    * and the blockSize must not be too close to the top of the dynamic range
    */
    Q_REQUIRE((poolSto != (void *)0)
              && (poolSize >= (uint32_t)sizeof(QFreeBlock))
              && ((QMPoolSize)(blockSize + (QMPoolSize)sizeof(QFreeBlock))
                    > blockSize));

    me->free_head = poolSto;

     /* round up the blockSize to fit an integer # free blocks, no division */
    me->blockSize = (QMPoolSize)sizeof(QFreeBlock);  /* start with just one */
    nblocks = (uint32_t)1;    /* # free blocks that fit in one memory block */
    while (me->blockSize < blockSize) {
        me->blockSize += (QMPoolSize)sizeof(QFreeBlock);
        ++nblocks;
    }
    blockSize = me->blockSize;      /* use the rounded-up value from now on */

                  /* the pool buffer must fit at least one rounded-up block */
    Q_ASSERT(poolSize >= (uint32_t)blockSize);

                             /* chain all blocks together in a free-list... */
    poolSize -= (uint32_t)blockSize;          /* don't count the last block */
    me->nTot  = (QMPoolCtr)1;         /* the last block already in the pool */
    fb = (QFreeBlock *)me->free_head; /* start at the head of the free list */
    while (poolSize >= (uint32_t)blockSize) {
        fb->next = &QF_PTR_AT_(fb, nblocks);/*point next link to next block */
        fb = fb->next;                         /* advance to the next block */
        poolSize -= (uint32_t)blockSize;  /* reduce the available pool size */
        ++me->nTot;                /* increment the number of blocks so far */
    }

    fb->next  = (QFreeBlock *)0;            /* the last link points to NULL */
    me->nFree = me->nTot;                            /* all blocks are free */
    me->nMin  = me->nTot;              /* the minimum number of free blocks */
    me->start = poolSto;             /* the original start this pool buffer */
    me->end   = fb;                          /* the last block in this pool */

    QS_BEGIN_(QS_QF_MPOOL_INIT, QS_priv_.mpObjFilter, me->start)
        QS_OBJ_(me->start);              /* the memory managed by this pool */
        QS_MPC_(me->nTot);                    /* the total number of blocks */
    QS_END_()
}
Пример #3
0
/*..........................................................................*/
void *QMPool_get(QMPool *me) {
    QFreeBlock *fb;
    QF_INT_LOCK_KEY_

    QF_INT_LOCK_();
    fb = (QFreeBlock *)me->free;                /* get a free block or NULL */
    if (fb != (QFreeBlock *)0) {                   /* free block available? */
        me->free = fb->next;     /* adjust list head to the next free block */
        --me->nFree;                                 /* one less free block */
        if (me->nMin > me->nFree) {
            me->nMin = me->nFree;            /* remember the minimum so far */
        }
    }

    QS_BEGIN_NOLOCK_(QS_QF_MPOOL_GET, 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_MPC_(me->nMin);    /* min number of free blocks ever in the pool */
    QS_END_NOLOCK_()

    QF_INT_UNLOCK_();
    return fb;            /* return the block or NULL pointer to the caller */
}
Пример #4
0
/*..........................................................................*/
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_();
}