static void
wmem_block_free(void *private_data, void *ptr)
{
    wmem_block_allocator_t *allocator = (wmem_block_allocator_t*) private_data;
    wmem_block_chunk_t     *chunk;

    chunk = WMEM_DATA_TO_CHUNK(ptr);

    if (chunk->jumbo) {
        wmem_block_free_jumbo(allocator, chunk);
        return;
    }

    g_assert(chunk->used);

    /* mark it as unused */
    chunk->used = FALSE;

    /* merge it with any other free chunks adjacent to it, so that contiguous
     * free space doesn't get fragmented */
    wmem_block_merge_free(allocator, chunk);

    /* Now cycle the recycler */
    wmem_block_cycle_recycler(allocator);
}
static void *
wmem_block_fast_realloc(void *private_data, void *ptr, const size_t size)
{
    wmem_block_fast_chunk_t *chunk;

    chunk = WMEM_DATA_TO_CHUNK(ptr);

    /* grow */
    if (chunk->len < size) {
        void *newptr;

        /* need to alloc and copy; free is no-op, so don't call it */
        newptr = wmem_block_fast_alloc(private_data, size);
        memcpy(newptr, ptr, chunk->len);

        return newptr;
    }

    /* shrink or same space - great we can do nothing */
    return ptr;
}
static void *
wmem_block_fast_realloc(void *private_data, void *ptr, const size_t size)
{
    wmem_block_fast_chunk_t *chunk;

    chunk = WMEM_DATA_TO_CHUNK(ptr);

    if (chunk->len == JUMBO_MAGIC) {
        wmem_block_fast_jumbo_t *block;

        block = ((wmem_block_fast_jumbo_t*)((guint8*)(chunk) - WMEM_JUMBO_HEADER_SIZE));
        block =  (wmem_block_fast_jumbo_t*)wmem_realloc(NULL, block,
                size + WMEM_JUMBO_HEADER_SIZE + WMEM_CHUNK_HEADER_SIZE);
        if (block->prev) {
            block->prev->next = block;
        }
        else {
            wmem_block_fast_allocator_t *allocator = (wmem_block_fast_allocator_t*) private_data;
            allocator->jumbo_list = block;
        }
        if (block->next) {
            block->next->prev = block;
        }
        return ((void*)((guint8*)(block) + WMEM_JUMBO_HEADER_SIZE + WMEM_CHUNK_HEADER_SIZE));
    }
    else if (chunk->len < size) {
        /* grow */
        void *newptr;

        /* need to alloc and copy; free is no-op, so don't call it */
        newptr = wmem_block_fast_alloc(private_data, size);
        memcpy(newptr, ptr, chunk->len);

        return newptr;
    }

    /* shrink or same space - great we can do nothing */
    return ptr;
}
Example #4
0
static void *
wmem_block_realloc(void *private_data, void *ptr, const size_t size)
{
    wmem_block_allocator_t *allocator = (wmem_block_allocator_t*) private_data;
    wmem_block_chunk_t     *chunk;

    chunk = WMEM_DATA_TO_CHUNK(ptr);

    if (chunk->jumbo) {
        return wmem_block_realloc_jumbo(allocator, chunk, size);
    }

    if (size > WMEM_CHUNK_DATA_LEN(chunk)) {
        /* grow */
        wmem_block_chunk_t *tmp;

        tmp = WMEM_CHUNK_NEXT(chunk);

        if (tmp && (!tmp->used) &&
            (size < WMEM_CHUNK_DATA_LEN(chunk) + tmp->len)) {
            /* the next chunk is free and has enough extra, so just grab
             * from that */
            size_t split_size;

            /* we ask for the next chunk to be split, but we don't end up
             * using the split chunk header (it just gets merged into this one),
             * so we want the split to be of (size - curdatalen - header_size).
             * However, this can underflow by header_size, so we do a quick
             * check here and floor the value to 0. */
            split_size = size - WMEM_CHUNK_DATA_LEN(chunk);

            if (split_size < WMEM_CHUNK_HEADER_SIZE) {
                split_size = 0;
            }
            else {
                split_size -= WMEM_CHUNK_HEADER_SIZE;
            }

            wmem_block_split_free_chunk(allocator, tmp, split_size);

            /* Now do a 'quickie' merge between the current block and the left-
             * hand side of the split. Simply calling wmem_block_merge_free
             * might confuse things, since we may temporarily have two blocks
             * to our right that are both free (and it isn't guaranteed to
             * handle that case). Update our 'next' count and last flag, and
             * our (new) successor's 'prev' count */
            chunk->len += tmp->len;
            chunk->last = tmp->last;
            tmp = WMEM_CHUNK_NEXT(chunk);
            if (tmp) {
                tmp->prev = chunk->len;
            }

            /* Now cycle the recycler */
            wmem_block_cycle_recycler(allocator);

            /* And return the same old pointer */
            return ptr;
        }
        else {
            /* no room to grow, need to alloc, copy, free */
            void *newptr;

            newptr = wmem_block_alloc(private_data, size);
            memcpy(newptr, ptr, WMEM_CHUNK_DATA_LEN(chunk));
            wmem_block_free(private_data, ptr);

            /* No need to cycle the recycler, alloc and free both did that
             * already */

            return newptr;
        }
    }
    else if (size < WMEM_CHUNK_DATA_LEN(chunk)) {
        /* shrink */
        wmem_block_split_used_chunk(allocator, chunk, size);

        /* Now cycle the recycler */
        wmem_block_cycle_recycler(allocator);

        return ptr;
    }

    /* no-op */
    return ptr;
}