slab* ObjectCache::InitSlab(slab* slab, void* pages, size_t byteCount, uint32 flags) { TRACE_CACHE(this, "construct (%p, %p .. %p, %lu)", slab, pages, ((uint8*)pages) + byteCount, byteCount); slab->pages = pages; slab->count = slab->size = byteCount / object_size; slab->free = NULL; size_t spareBytes = byteCount - (slab->size * object_size); if ((this->flags & CACHE_ALIGN_ON_SIZE) != 0) { slab->offset = cache_color_cycle; if (slab->offset > spareBytes) cache_color_cycle = slab->offset = 0; else cache_color_cycle += kCacheColorPeriod; } else slab->offset = 0; TRACE_CACHE(this, " %lu objects, %lu spare bytes, offset %lu", slab->size, spareBytes, slab->offset); uint8* data = ((uint8*)pages) + slab->offset; CREATE_PARANOIA_CHECK_SET(slab, "slab"); for (size_t i = 0; i < slab->size; i++) { status_t status = B_OK; if (constructor) status = constructor(cookie, data); if (status != B_OK) { data = ((uint8*)pages) + slab->offset; for (size_t j = 0; j < i; j++) { if (destructor) destructor(cookie, data); data += object_size; } DELETE_PARANOIA_CHECK_SET(slab); return NULL; } _push(slab->free, object_to_link(data, object_size)); ADD_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, slab, &object_to_link(data, object_size)->next, sizeof(void*)); data += object_size; } return slab; }
void ObjectCache::ReturnObjectToSlab(slab* source, void* object, uint32 flags) { if (source == NULL) { panic("object_cache: free'd object has no slab"); return; } ParanoiaChecker _(source); uint8* data = (uint8*) object; if (data < source->pages || data >= (uint8*) source->pages + source->size * object_size) { panic("object_cache: free'd object does not belong to slab"); } intptr_t objectOffset = data - source->offset - (uint8*) source->pages; if (objectOffset % object_size != 0) { panic("object_cache: returning a wrong pointer to a slab object"); } object_link* link = object_to_link(object, object_size); TRACE_CACHE(this, "returning %p (%p) to %p, %lu used (%lu empty slabs).", object, link, source, source->size - source->count, empty_count); _push(source->free, link); source->count++; used_count--; ADD_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, source, &link->next, sizeof(void*)); if (source->count == source->size) { partial.Remove(source); if (empty_count < pressure && total_objects - used_count - source->size >= min_object_reserve) { empty_count++; empty.Add(source); } else { ReturnSlab(source, flags); } } else if (source->count == 1) { full.Remove(source); partial.Add(source); } }
void ObjectCache::ReturnObjectToSlab(slab* source, void* object, uint32 flags) { if (source == NULL) { panic("object_cache: free'd object has no slab"); return; } ParanoiaChecker _(source); object_link* link = object_to_link(object, object_size); TRACE_CACHE(this, "returning %p (%p) to %p, %lu used (%lu empty slabs).", object, link, source, source->size - source->count, empty_count); _push(source->free, link); source->count++; used_count--; ADD_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, source, &link->next, sizeof(void*)); if (source->count == source->size) { partial.Remove(source); if (empty_count < pressure && total_objects - used_count - source->size >= min_object_reserve) { empty_count++; empty.Add(source); } else { ReturnSlab(source, flags); } } else if (source->count == 1) { full.Remove(source); partial.Add(source); } }