Пример #1
0
// return next meta, if any
meta_t* _slab_free_erase(meta_t* meta)
{
    meta_t *next, *prev;
    if (!meta) {
        return NULL;
    }

    // prev and next free link
    if (meta->free_prev > 0) {
        prev = META(meta, meta->free_prev);
    } else {
        prev = NULL;
    }
    if (meta->free_next > 0) {
        next = META(meta, meta->free_next);
    } else {
        next = NULL;
    }

    // relink
    if (next) {
        next->free_prev = prev ? META_SHIFT(prev) : -1;
    }
    if (prev) {
        prev->free_next = next ? META_SHIFT(next) : -1;
    }

    // erase self link
    meta->free_prev = -1;
    meta->free_next = -1;
    return next;
}
Пример #2
0
void _slab_free_insert(meta_t* meta, meta_t* insert)
{
    meta_t* next;
    if (!meta || !insert) return;
    if (meta->free_next > 0) {
        next = META(meta, meta->free_next);
        insert->free_next = META_SHIFT(next);
        next->free_prev = META_SHIFT(insert);
    }
    insert->free_prev = META_SHIFT(meta);
    meta->free_next = META_SHIFT(insert);
}
Пример #3
0
void* _slab_alloc(page_t* page, list_head_t* head, size_t sz)
{
    int16_t shift;
    meta_t* meta, *next, *split;

    // no free memory
    if (page->free <= 0 || page->remain < (int)sz + (int)META_SIZE) {
        return NULL;
    }

    // loop free memory
    shift = page->free;
    while (shift > 0) {
        meta = PAGE_META(page, shift);
        shift = meta->free_next;

        // not enough, ignore
        if (meta->size < (int)sz) {
            meta = NULL;
            continue;
        }

        // just fit, erase from free list
        else if (meta->size <= (int)(sz + META_SIZE)) {
            next = _slab_free_erase(meta);
            // erase free-link head
            if (META_SHIFT(meta) == page->free) {
                page->free = next ? META_SHIFT(next) : -1;
            }
            meta->color |= META_COLOR_ALLOC;
            break;
        }

        // do split
        else {
            split = _slab_free_split(meta, sz);
            _slab_free_replace(meta, split);

            if (META_SHIFT(meta) == page->free) {
                page->free = META_SHIFT(split);
            }
            meta->color |= META_COLOR_ALLOC;
            break;
        }
    }
    if (meta) {
        page->remain -= (META_SIZE + meta->size);
        _slab_page_erase(page, head);
        return META_MEM(meta);
    }
    return NULL;
}
Пример #4
0
static void
_slab_free_replace(meta_t* meta, meta_t* replace) {
    if (!meta || !replace) {
        return;
    }
    if (meta->free_prev > 0) {
        meta_t* prev = META(meta, meta->free_prev);
        prev->free_next = META_SHIFT(replace);
        replace->free_prev = META_SHIFT(prev);
    } else {
        replace->free_prev = -1;
    }
    if (meta->free_next > 0) {
        meta_t* next = META(meta, meta->free_next);
        next->free_prev = META_SHIFT(replace);
        replace->free_next = META_SHIFT(next);
    } else {
        replace->free_next = -1;
    }
}
Пример #5
0
// return next meta, if any
static meta_t*
_slab_free_erase(meta_t* meta) {
    if (!meta) {
        return NULL;
    }
    // prev and next free link
    meta_t* prev = (meta->free_prev > 0) ? META(meta, meta->free_prev) : NULL;
    meta_t* next = (meta->free_next > 0) ? META(meta, meta->free_next) : NULL;
    // relink
    if (next) {
        next->free_prev = prev ? META_SHIFT(prev) : -1;
    }
    if (prev) {
        prev->free_next = next ? META_SHIFT(next) : -1;
    }
    // erase self link
    meta->free_prev = -1;
    meta->free_next = -1;
    return next;
}
Пример #6
0
// check next meta whether free, if free, then do quick merge
// replace_next == 0 means meta will replace next in free link
// return 0 means do quick merge success
int _slab_free_quick_merge(meta_t* meta, int replace_next)
{
    meta_t* next, *prev;
    page_t* page = META_PAGE(meta);
    int shift = META_SHIFT(meta) + META_SIZE + meta->size;
    if (shift < getpagesize()) {
        next = META(meta, shift);
        if (!(next->color & META_COLOR_ALLOC)) {
            prev = next->free_prev > 0 ? PAGE_META(page, next->free_prev) : NULL;
            // quick merge with next
            meta->size += next->size + META_SIZE;
            if (replace_next == 0) {
                _slab_free_replace(next, meta);
                if (META_SHIFT(next) == page->free) {
                    page->free = META_SHIFT(meta);
                }
            }
            // quick merge with prev
            if (prev && META_SHIFT(prev) + META_SIZE + prev->size == META_SHIFT(meta)) {
                prev->size += META_SIZE + meta->size;
                prev->free_next = meta->free_next;
                next = meta->free_next > 0 ? PAGE_META(page, meta->free_next) : NULL;
                if (next) {
                    next->free_prev = META_SHIFT(prev);
                }
            }
            return 0;
        }
    }
    return -1;
}