static void decommitMBlocks()

in rts/sm/MBlock.c [223:329]


static void decommitMBlocks(char *addr, uint32_t n)
{
    struct free_list *iter, *prev;
    W_ size = MBLOCK_SIZE * (W_)n;
    W_ address = (W_)addr;

    osDecommitMemory(addr, size);

    prev = NULL;
    for (iter = free_list_head; iter != NULL; iter = iter->next)
    {
        prev = iter;

        if (iter->address + iter->size < address)
            continue;

        if (iter->address + iter->size == address) {
            iter->size += size;

            if (address + size == mblock_high_watermark) {
                mblock_high_watermark -= iter->size;
                if (iter->prev) {
                    iter->prev->next = NULL;
                } else {
                    ASSERT(iter == free_list_head);
                    free_list_head = NULL;
                }
                stgFree(iter);
                return;
            }

            if (iter->next &&
                iter->next->address == iter->address + iter->size) {
                struct free_list *next;

                next = iter->next;
                iter->size += next->size;
                iter->next = next->next;

                if (iter->next) {
                    iter->next->prev = iter;

                    /* We don't need to consolidate more */
                    ASSERT(iter->next->address > iter->address + iter->size);
                }

                stgFree(next);
            }
            return;
        } else if (address + size == iter->address) {
            iter->address = address;
            iter->size += size;

            /* We don't need to consolidate backwards
               (because otherwise it would have been handled by
               the previous iteration) */
            if (iter->prev) {
                ASSERT(iter->prev->address + iter->prev->size < iter->address);
            }
            return;
        } else {
            struct free_list *new_iter;

            /* All other cases have been handled */
            ASSERT(iter->address > address + size);

            new_iter = stgMallocBytes(sizeof(struct free_list), "freeMBlocks");
            new_iter->address = address;
            new_iter->size = size;
            new_iter->next = iter;
            new_iter->prev = iter->prev;
            if (new_iter->prev) {
                new_iter->prev->next = new_iter;
            } else {
                ASSERT(iter == free_list_head);
                free_list_head = new_iter;
            }
            iter->prev = new_iter;
            return;
        }
    }

    /* We're past the last free list entry, so we must
       be the highest allocation so far
    */
    ASSERT(address + size <= mblock_high_watermark);

    /* Fast path the case of releasing high or all memory */
    if (address + size == mblock_high_watermark) {
        mblock_high_watermark -= size;
    } else {
        struct free_list *new_iter;

        new_iter = stgMallocBytes(sizeof(struct free_list), "freeMBlocks");
        new_iter->address = address;
        new_iter->size = size;
        new_iter->next = NULL;
        new_iter->prev = prev;
        if (new_iter->prev) {
            ASSERT(new_iter->prev->next == NULL);
            new_iter->prev->next = new_iter;
        } else {
            ASSERT(free_list_head == NULL);
            free_list_head = new_iter;
        }
    }
}