Beispiel #1
0
/* Inserts in order a chunk into the free list.  Caller adjusts heap state */
static PmReturn_t
heap_linkToFreelist(pPmHeapDesc_t pchunk)
{
    uint16_t size;
    pPmHeapDesc_t pscan;

    /* Ensure the object is already free */
    C_ASSERT(OBJ_GET_FREE(pchunk) != 0);

    /* If free list is empty, add to head of list */
    if (pmHeap.pfreelist == C_NULL)
    {
        pmHeap.pfreelist = pchunk;
        pchunk->next = C_NULL;
        pchunk->prev = C_NULL;

        return PM_RET_OK;
    }

    /* Scan free list for insertion point */
    pscan = pmHeap.pfreelist;
    size = OBJ_GET_SIZE(pchunk);
    while ((OBJ_GET_SIZE(pscan) < size) && (pscan->next != C_NULL))
    {
        pscan = pscan->next;
    }

    /*
     * Insert chunk after the scan chunk (next is NULL).
     * This is a slightly rare case where the last chunk in the free list
     * is smaller than the chunk being freed.
     */
    if (size > OBJ_GET_SIZE(pscan))
    {
        pchunk->next = pscan->next;
        pscan->next = pchunk;
        pchunk->prev = pscan;
    }

    /* Insert chunk before the scan chunk */
    else
    {
        pchunk->next = pscan;
        pchunk->prev = pscan->prev;

        /* If chunk will be first item in free list */
        if (pscan->prev == C_NULL)
        {
            pmHeap.pfreelist = pchunk;
        }
        else
        {
            pscan->prev->next = pchunk;
        }
        pscan->prev = pchunk;
    }

    return PM_RET_OK;
}
Beispiel #2
0
static void
heap_gcPrintFreelist(void)
{
    pPmHeapDesc_t pchunk = pmHeap.pfreelist;

    printf("DEBUG: pmHeap.avail = %d\n", pmHeap.avail);
    printf("DEBUG: freelist:\n");
    while (pchunk != C_NULL)
    {
        printf("DEBUG:     free chunk (%d bytes) @ 0x%0x\n",
               OBJ_GET_SIZE(pchunk), (int)pchunk);
        pchunk = pchunk->next;
    }
}
Beispiel #3
0
/* Releases chunk to the free list */
PmReturn_t
heap_freeChunk(pPmObj_t ptr)
{
    PmReturn_t retval;

    C_DEBUG_PRINT(VERBOSITY_HIGH, "heap_freeChunk(), id=%p, s=%d\n",
                  ptr, OBJ_GET_SIZE(ptr));

    /* Ensure the chunk falls within the heap */
    C_ASSERT(((uint8_t *)ptr >= pmHeap.base)
             && ((uint8_t *)ptr < pmHeap.base + HEAP_SIZE));

    /* Insert the chunk into the freelist */
    OBJ_SET_FREE(ptr, 1);

    /* Clear type so that heap descriptor's size's upper byte is zero */
    OBJ_SET_TYPE(ptr, 0);
    retval = heap_linkToFreelist((pPmHeapDesc_t)ptr);
    PM_RETURN_IF_ERROR(retval);

    /* Increase heap available amount */
    pmHeap.avail += OBJ_GET_SIZE(ptr);
    return retval;
}
Beispiel #4
0
/* Removes the given chunk from the free list; leaves list in sorted order */
static PmReturn_t
heap_unlinkFromFreelist(pPmHeapDesc_t pchunk)
{
    C_ASSERT(pchunk != C_NULL);

    pmHeap.avail -= OBJ_GET_SIZE(pchunk);

    if (pchunk->next != C_NULL)
    {
        pchunk->next->prev = pchunk->prev;
    }

    /* If pchunk was the first chunk in the free list, update the heap ptr */
    if (pchunk->prev == C_NULL)
    {
        pmHeap.pfreelist = pchunk->next;
    }
    else
    {
        pchunk->prev->next = pchunk->next;
    }

    return PM_RET_OK;
}
Beispiel #5
0
/**
 * Obtains a chunk of memory from the free list
 *
 * Performs the Best Fit algorithm.
 * Iterates through the freelist to see if a chunk of suitable size exists.
 * Shaves a chunk to perfect size iff the remainder is greater than
 * the minimum chunk size.
 *
 * @param size Requested chunk size
 * @param r_pchunk Return ptr to chunk
 * @return Return status
 */
static PmReturn_t
heap_getChunkImpl(uint16_t size, uint8_t **r_pchunk)
{
    PmReturn_t retval;
    pPmHeapDesc_t pchunk;
    pPmHeapDesc_t premainderChunk;

    C_ASSERT(r_pchunk != C_NULL);

    /* Skip to the first chunk that can hold the requested size */
    pchunk = pmHeap.pfreelist;
    while ((pchunk != C_NULL) && (OBJ_GET_SIZE(pchunk) < size))
    {
        pchunk = pchunk->next;
    }

    /* No chunk of appropriate size was found, raise OutOfMemory exception */
    if (pchunk == C_NULL)
    {
        *r_pchunk = C_NULL;
        PM_RAISE(retval, PM_RET_EX_MEM);
        return retval;
    }

    /* Remove the chunk from the free list */
    retval = heap_unlinkFromFreelist(pchunk);
    PM_RETURN_IF_ERROR(retval);

    /* Check if a chunk should be carved from what is available */
    if (OBJ_GET_SIZE(pchunk) - size >= HEAP_MIN_CHUNK_SIZE)
    {
        /* Create the heap descriptor for the remainder chunk */
        premainderChunk = (pPmHeapDesc_t)((uint8_t *)pchunk + size);
        OBJ_SET_FREE(premainderChunk, 1);
        OBJ_SET_SIZE(premainderChunk, OBJ_GET_SIZE(pchunk) - size);

        /* Put the remainder chunk back in the free list */
        retval = heap_linkToFreelist(premainderChunk);
        PM_RETURN_IF_ERROR(retval);

        /* Convert the chunk from a heap descriptor to an object descriptor */
        OBJ_SET_SIZE(pchunk, 0);
        OBJ_SET_FREE(pchunk, 0);
        OBJ_SET_SIZE(pchunk, size);

        C_DEBUG_PRINT(VERBOSITY_HIGH,
                      "heap_getChunkImpl()carved, id=%p, s=%d\n", pchunk,
                      size);
    }
    else
    {
        /* Set chunk's type to none (overwrites size field's high byte) */
        OBJ_SET_TYPE((pPmObj_t)pchunk, OBJ_TYPE_NON);
        OBJ_SET_FREE(pchunk, 0);

        C_DEBUG_PRINT(VERBOSITY_HIGH,
                      "heap_getChunkImpl()exact, id=%p, s=%d\n", pchunk,
                      OBJ_GET_SIZE(pchunk));
    }

    /*
     * Set the chunk's GC mark so it will be collected during the next GC cycle
     * if it is not reachable
     */
    OBJ_SET_GCVAL(pchunk, pmHeap.gcval);

    /* Return the chunk */
    *r_pchunk = (uint8_t *)pchunk;

    return retval;
}
Beispiel #6
0
/*
 * Reclaims any object that does not have a current mark.
 * Puts it in the free list.  Coalesces all contiguous free chunks.
 */
static PmReturn_t
heap_gcSweep(void)
{
    PmReturn_t retval;
    pPmObj_t pobj;
    pPmHeapDesc_t pchunk;
    uint16_t totalchunksize;

#if USE_STRING_CACHE
    retval = heap_purgeStringCache(pmHeap.gcval);
#endif

    /* Start at the base of the heap */
    pobj = (pPmObj_t)pmHeap.base;
    while ((uint8_t *)pobj < &pmHeap.base[PM_HEAP_SIZE])
    {
        /* Skip to the next unmarked or free chunk within the heap */
        while (!OBJ_GET_FREE(pobj)
               && (OBJ_GET_GCVAL(pobj) == pmHeap.gcval)
               && ((uint8_t *)pobj < &pmHeap.base[PM_HEAP_SIZE]))
        {
            pobj = (pPmObj_t)((uint8_t *)pobj + OBJ_GET_SIZE(pobj));
        }

        /* Stop if reached the end of the heap */
        if ((uint8_t *)pobj >= &pmHeap.base[PM_HEAP_SIZE])
        {
            break;
        }

        /* Accumulate the sizes of all consecutive unmarked or free chunks */
        totalchunksize = 0;

        /* Coalesce all contiguous free chunks */
        pchunk = (pPmHeapDesc_t)pobj;
        while (OBJ_GET_FREE(pchunk)
               || (!OBJ_GET_FREE(pchunk)
                   && (OBJ_GET_GCVAL(pchunk) != pmHeap.gcval)))
        {
            if ((totalchunksize + OBJ_GET_SIZE(pchunk))
                > HEAP_MAX_FREE_CHUNK_SIZE)
            {
                break;
            }
            totalchunksize = totalchunksize + OBJ_GET_SIZE(pchunk);

            /*
             * If the chunk is already free, unlink it because its size
             * is about to change
             */
            if (OBJ_GET_FREE(pchunk))
            {
                retval = heap_unlinkFromFreelist(pchunk);
                PM_RETURN_IF_ERROR(retval);
            }

            /* Otherwise free and reclaim the unmarked chunk */
            else
            {
                OBJ_SET_TYPE(pchunk, 0);
                OBJ_SET_FREE(pchunk, 1);
            }

            C_DEBUG_PRINT(VERBOSITY_HIGH, "heap_gcSweep(), id=%p, s=%d\n",
                          pchunk, OBJ_GET_SIZE(pchunk));

            /* Proceed to the next chunk */
            pchunk = (pPmHeapDesc_t)
                ((uint8_t *)pchunk + OBJ_GET_SIZE(pchunk));

            /* Stop if it's past the end of the heap */
            if ((uint8_t *)pchunk >= &pmHeap.base[PM_HEAP_SIZE])
            {
                break;
            }
        }

        /* Set the heap descriptor data */
        OBJ_SET_FREE(pobj, 1);
        OBJ_SET_SIZE(pobj, totalchunksize);

        /* Insert chunk into free list */
        retval = heap_linkToFreelist((pPmHeapDesc_t)pobj);
        PM_RETURN_IF_ERROR(retval);

        /* Continue to the next chunk */
        pobj = (pPmObj_t)pchunk;
    }

    return PM_RET_OK;
}
Beispiel #7
0
/*
 * Reclaims any object that doesn't have a current mark.
 * Puts it in the free list.  Coalesces all contiguous free chunks.
 */
static PmReturn_t
heap_gcSweep(void)
{
    PmReturn_t retval;
    pPmObj_t pobj;
    pPmHeapDesc_t pchunk;
    uint16_t totalchunksize;
    uint16_t additionalheapsize;

    /* Start at the base of the heap */
    pobj = (pPmObj_t)pmHeap.base;
    while ((uint8_t *)pobj < &pmHeap.base[HEAP_SIZE])
    {
        /* Skip to the next unmarked or free chunk within the heap */
        while (!OBJ_GET_FREE(pobj)
               && (OBJ_GET_GCVAL(pobj) == pmHeap.gcval)
               && ((uint8_t *)pobj < &pmHeap.base[HEAP_SIZE]))
        {
            pobj = (pPmObj_t)((uint8_t *)pobj + OBJ_GET_SIZE(pobj));
/*printf("Object is at addr <%x>\n",(uint32_t)pobj);*/
#if 0
printf("pobj=");obj_print(pobj,0);printf("; type=%x; size=%x\n",OBJ_GET_TYPE(pobj),OBJ_GET_SIZE(pobj));
#endif
        }

        /* Stop if reached the end of the heap */
        if ((uint8_t *)pobj >= &pmHeap.base[HEAP_SIZE])
        {
            break;
        }

        /* Accumulate the sizes of all consecutive unmarked or free chunks */
        totalchunksize = 0;
        additionalheapsize = 0;

        /* Coalesce all contiguous free chunks */
        pchunk = (pPmHeapDesc_t)pobj;
        while (OBJ_GET_FREE(pchunk)
               || (!OBJ_GET_FREE(pchunk)
                   && (OBJ_GET_GCVAL(pchunk) != pmHeap.gcval)))
        {
            totalchunksize += OBJ_GET_SIZE(pchunk);

            /*
             * If the chunk is already free, unlink it because its size
             * is about to change
             */
            if (OBJ_GET_FREE(pchunk))
            {
                retval = heap_unlinkFromFreelist(pchunk);
                PM_RETURN_IF_ERROR(retval);
            }

            /* Otherwise free and reclaim the unmarked chunk */
            else
            {
                OBJ_SET_TYPE(pchunk, 0);
                OBJ_SET_FREE(pchunk, 1);
                additionalheapsize += OBJ_GET_SIZE(pchunk);
            }

            C_DEBUG_PRINT(VERBOSITY_HIGH, "heap_gcSweep(), id=%p, s=%d\n",
                          pchunk, OBJ_GET_SIZE(pchunk));

#if 0
            /* It's possible for 0-sized chunks to exist (which makes no sense) TODO:solve */
            /* They result in infinite loops, so we must curtail them */
            if (OBJ_GET_SIZE(pchunk) == 0)
            {
                break;
            }
#endif

            /* Proceed to the next chunk */
            pchunk = (pPmHeapDesc_t)
                     ((uint8_t *)pchunk + OBJ_GET_SIZE(pchunk));

            /* Stop if it's past the end of the heap */
            if ((uint8_t *)pchunk >= &pmHeap.base[HEAP_SIZE])
            {
                break;
            }
        }

        /* Adjust the heap stats */
        pmHeap.avail += additionalheapsize;

        /* Set the heap descriptor data */
        OBJ_SET_FREE(pobj, 1);
        OBJ_SET_SIZE(pobj, totalchunksize);

#if 0
        /* avoid loops by breaking on 0-size */
        if (totalchunksize == 0)
        {
            break;
        }
#endif

        /* Insert chunk into free list */
        retval = heap_linkToFreelist((pPmHeapDesc_t)pobj);
        PM_RETURN_IF_ERROR(retval);

        /* Continue to the next chunk */
        pobj = (pPmObj_t)pchunk;
    }

    return PM_RET_OK;
}