ClRcT
clPoolShrink(
    ClPoolT                     poolHandle,
    const ClPoolShrinkOptionsT* pShrinkOptions)
{
    ClRcT          rc          = CL_OK;
    ClPoolHeaderT* pPoolHeader = (ClPoolHeaderT*)poolHandle;
    ClPoolShrinkOptionsT defaultShrinkOptions;
    defaultShrinkOptions.shrinkFlags = CL_POOL_SHRINK_DEFAULT;

    NULL_CHECK (pPoolHeader);
    if (pShrinkOptions == NULL)
    {
        pShrinkOptions = &defaultShrinkOptions;
    }
    CL_POOL_LOG(CL_LOG_TRACE,
                "Shrinking %d byte pool of %d chunksize",
                pPoolHeader->poolConfig.incrementPoolSize,
                pPoolHeader->poolConfig.chunkSize);

    CL_POOL_LOCK (pPoolHeader);
    rc = CL_POOL_SHRINK_FREELIST (pPoolHeader, pShrinkOptions);
    CL_POOL_UNLOCK(pPoolHeader);

    if(rc != CL_OK)
    {
        CL_DEBUG_PRINT (CL_DEBUG_ERROR, ("Error in shrinking free list\n"));
        CL_POOL_LOG(CL_LOG_ERROR,
                    "Error shrinking %d byte pool of %d chunksize",
                    pPoolHeader->poolConfig.incrementPoolSize,
                    pPoolHeader->poolConfig.chunkSize);
    }
    return rc;
}
ClRcT
clPoolFree(
    ClUint8T*   pChunk,
    void*       pCookie)
{
    ClRcT                   rc                  = CL_OK;
    ClPoolHeaderT*          pPoolHeader         = NULL;
    ClExtendedPoolHeaderT*  pExtendedPoolHeader = NULL;
    ClUint32T               freeChunk           = 0;
    ClUint32T               chunkSize           = 0;
    ClFreeListHeaderT*      pCurrentFreeList    = NULL;

    NULL_CHECK (pChunk);
    NULL_CHECK (pCookie);

    pExtendedPoolHeader = (ClExtendedPoolHeaderT*)pCookie;
    pPoolHeader = pExtendedPoolHeader->pPoolHeader;

    CL_POOL_LOG(CL_LOG_SEV_TRACE,"freeing chunk  pChunk = %p,extended pool = %p\n", pChunk,(void*)pExtendedPoolHeader);

    CL_POOL_LOCK (pPoolHeader);

    chunkSize = pPoolHeader->poolConfig.chunkSize;

    CL_POOL_REVOKE_SIZE(pPoolHeader->flags,chunkSize);

    CL_POOL_FREE_LIST_GET (pChunk, pExtendedPoolHeader, pCurrentFreeList);

    pCurrentFreeList->pChunk = (ClUint8T*)pChunk;
    pCurrentFreeList->pNextFreeChunk = pExtendedPoolHeader->pFirstFreeChunk;
    pExtendedPoolHeader->pFirstFreeChunk = pCurrentFreeList;

    CL_POOL_STATS_UPDATE_FREES (pPoolHeader);
    freeChunk = ++pExtendedPoolHeader->numFreeChunks;
    if (freeChunk == 1)
    {
        /*Was full before. Move it to partial*/
        CL_POOL_LOG(CL_LOG_SEV_TRACE,"Dequeuing extended pool %p from full list and moving the extended pool to partial list\n", (void*)pExtendedPoolHeader);
        CL_POOL_EXTENDED_FULLLIST_DEQUEUE (pPoolHeader, pExtendedPoolHeader);
        CL_POOL_EXTENDED_PARTIALLIST_QUEUE (pPoolHeader, pExtendedPoolHeader);
    }
    if (freeChunk == pExtendedPoolHeader->numChunks)
    {
        /*
         *  Add to the free extended pool list after deleting from the partial
         *  list
         */
        CL_POOL_LOG(CL_LOG_SEV_TRACE, "Dequeuing extended pool %p from partial list and moving the extended pool to free list\n", (void*)pExtendedPoolHeader);
        CL_POOL_EXTENDED_PARTIALLIST_DEQUEUE(pPoolHeader,pExtendedPoolHeader);
        CL_POOL_EXTENDED_FREELIST_QUEUE(pPoolHeader,pExtendedPoolHeader);
    }
    CL_POOL_UNLOCK(pPoolHeader);
    rc = CL_OK;
    return rc;
}
ClRcT
clPoolStatsGet(
    ClPoolT         pool,
    ClPoolStatsT*   pPoolStats)
{
    ClRcT           rc          = CL_OK;
    ClPoolHeaderT*  pPoolHeader = (ClPoolHeaderT*)pool;

    NULL_CHECK (pPoolStats);
    NULL_CHECK (pPoolHeader);

    CL_POOL_LOCK (pPoolHeader);
    memcpy (pPoolStats, &pPoolHeader->stats, sizeof (*pPoolStats));
    /*store the pool config*/
    memcpy(&(pPoolStats->poolConfig), &(pPoolHeader->poolConfig),
        sizeof (pPoolStats->poolConfig));
    CL_POOL_UNLOCK(pPoolHeader);

    return rc;
}
ClRcT
clPoolDestroy(
    ClPoolT poolHandle)
{
    ClRcT rc = CL_OK;
    ClPoolHeaderT *pPoolHeader = (ClPoolHeaderT*)poolHandle;
    ClPoolFlagsT flags;

    NULL_CHECK (pPoolHeader);
    flags = pPoolHeader->flags;
    CL_POOL_LOG(CL_LOG_NOTICE,
                "Destroying %d byte pool of %d chunksize",
                pPoolHeader->poolConfig.incrementPoolSize,
                pPoolHeader->poolConfig.chunkSize
                );
    CL_POOL_LOCK (pPoolHeader);
    rc = clPoolDestroyWithForce (pPoolHeader, CL_FALSE);
    CL_POOL_UNLOCK (pPoolHeader);

    if (rc != CL_OK)
    {
        CL_DEBUG_PRINT (CL_DEBUG_ERROR, ("Error destroying the pool\n"));
        CL_POOL_LOG(CL_LOG_ERROR,
                    "Error destroying %d byte pool of %d chunksize",
                    pPoolHeader->poolConfig.incrementPoolSize,
                    pPoolHeader->poolConfig.chunkSize);
        goto out;
    }
    /*
     * This is pretty dangerous and hence any users of this pool
     * go for a toss.
     * But destroy shouldnt be used on pre-defined pools
     * with pools in use anyway.
     */
    CL_POOL_LOCK_DESTROY (pPoolHeader);
    CL_POOL_FREE_EXTERNAL (flags, (void*)pPoolHeader, sizeof (*pPoolHeader));
    out:
    return rc;
}
ClRcT
clPoolDestroyForce(
    ClPoolT poolHandle)
{
    ClRcT           rc              = CL_OK;
    ClPoolHeaderT   *pPoolHeader    = (ClPoolHeaderT*)poolHandle;
    ClPoolFlagsT    flags;

    NULL_CHECK (pPoolHeader);
    flags = pPoolHeader->flags;
    CL_POOL_LOG(CL_LOG_TRACE,
                "Force destroying %d byte pool of %d chunksize",
                pPoolHeader->poolConfig.incrementPoolSize,
                pPoolHeader->poolConfig.chunkSize
                );
    CL_POOL_LOCK (pPoolHeader);
    rc = clPoolDestroyWithForce (pPoolHeader, CL_TRUE);
    CL_POOL_UNLOCK (pPoolHeader);
    CL_POOL_LOCK_DESTROY (pPoolHeader);
    CL_POOL_FREE_EXTERNAL (flags, (void*)pPoolHeader, sizeof (*pPoolHeader));
    return rc;
}
ClRcT
clPoolAllocate(
    ClPoolT     poolHandle,
    ClUint8T**  ppChunk,
    void**      ppCookie)
{
    ClPoolHeaderT*          pPoolHeader         = NULL;
    ClRcT                   rc                  = CL_OK;
    ClFreeListHeaderT*      pFreeChunk          = NULL;
    ClExtendedPoolHeaderT*  pExtendedPoolHeader = NULL;

    pPoolHeader = (ClPoolHeaderT*)poolHandle;
    NULL_CHECK (pPoolHeader);
    NULL_CHECK (ppChunk);
    NULL_CHECK (ppCookie);

    CL_POOL_LOCK (pPoolHeader);

    if(CL_POOL_GRANT_SIZE(pPoolHeader->flags,
                          pPoolHeader->poolConfig.chunkSize) == CL_FALSE)
    {
        rc = CL_POOL_RC(CL_ERR_NO_MEMORY);
        CL_DEBUG_PRINT(CL_DEBUG_ERROR,("Request of %d bytes would exceed process upper limit\n",pPoolHeader->poolConfig.chunkSize));
        goto out_unlock;
    }

    /*Check for a partially full queue*/
    if (CL_POOL_EXTENDED_PARTIALLIST_EMPTY (pPoolHeader))
    {
        /*Look for an extended pool in the free list*/
        if (CL_POOL_EXTENDED_FREELIST_EMPTY (pPoolHeader))
        {
            /*Grow the extended pool*/
            rc = clPoolExtend(poolHandle);
            if(rc != CL_OK)
            {
                CL_DEBUG_PRINT (CL_DEBUG_ERROR,
                        ("Pool extension error for chunksize:%d\n",
                         pPoolHeader->poolConfig.chunkSize));
                CL_POOL_LOG(CL_LOG_ERROR,
                            "Pool allocate failed to extend %d byte pool of %d chunksize",
                            pPoolHeader->poolConfig.incrementPoolSize,
                            pPoolHeader->poolConfig.chunkSize);
                goto out_unlock;
            }
        }
        CL_POOL_EXTENDED_FREELIST_POP_DEQUEUE (pPoolHeader,
                pExtendedPoolHeader);
        CL_POOL_EXTENDED_PARTIALLIST_QUEUE (pPoolHeader ,pExtendedPoolHeader);
    }
    /*
     * We are here when we have a free chunk:
     * Point of no-return
     */
    CL_POOL_EXTENDED_PARTIALLIST_POP (pPoolHeader, pExtendedPoolHeader);

    pFreeChunk = pExtendedPoolHeader->pFirstFreeChunk;
    pExtendedPoolHeader->pFirstFreeChunk = pFreeChunk->pNextFreeChunk;
    *ppChunk = (ClUint8T*)pFreeChunk->pChunk;
    *ppCookie = (void *)pExtendedPoolHeader;

    CL_POOL_STATS_UPDATE_ALLOCS (pPoolHeader);

    --pExtendedPoolHeader->numFreeChunks;

    CL_DEBUG_PRINT (CL_DEBUG_TRACE,
            ("pExtendedPoolHeader = %p pExtendedPoolHeader->numFreeChunks "
             "= %d pPoolHeader->poolConfig.chunkSize = %d from address = %p\n",
             (void*)pExtendedPoolHeader, pExtendedPoolHeader->numFreeChunks,
                pPoolHeader->poolConfig.chunkSize, (void*)pFreeChunk->pChunk));

    /*
     * Was free partially but now full.
     * move it to full list.
     */
    if (pExtendedPoolHeader->numFreeChunks == 0)
    {
        CL_DEBUG_PRINT (CL_DEBUG_TRACE,
            ("Dequeuing extended pool %p from partial list and queueing it to "
             "full list\n", (void*)pExtendedPoolHeader));
        CL_POOL_EXTENDED_PARTIALLIST_DEQUEUE (pPoolHeader, pExtendedPoolHeader);
        CL_POOL_EXTENDED_FULLLIST_QUEUE (pPoolHeader, pExtendedPoolHeader);
    }
    out_unlock:
    CL_POOL_UNLOCK (pPoolHeader);
    return rc;
}