pushed the slab init a bit deeper. added a object cache based allocator, including a bootstrap mechanism to have it init during bootup.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20896 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -16,14 +16,15 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* create_object_cache_etc flags */
|
|
||||||
enum {
|
enum {
|
||||||
|
/* create_object_cache_etc flags */
|
||||||
CACHE_NO_DEPOT = 1 << 0,
|
CACHE_NO_DEPOT = 1 << 0,
|
||||||
};
|
|
||||||
|
|
||||||
/* object_cache_alloc flags */
|
/* object_cache_alloc flags */
|
||||||
enum {
|
CACHE_DONT_SLEEP = 1 << 8,
|
||||||
CACHE_DONT_SLEEP = 1 << 0,
|
|
||||||
|
/* internal */
|
||||||
|
CACHE_DURING_BOOT = 1 << 31
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct object_cache object_cache;
|
typedef struct object_cache object_cache;
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ typedef struct object_depot {
|
|||||||
} object_depot;
|
} object_depot;
|
||||||
|
|
||||||
|
|
||||||
status_t object_depot_init(object_depot *depot,
|
status_t object_depot_init(object_depot *depot, uint32 flags,
|
||||||
void (*return_object)(object_depot *, void *));
|
void (*return_object)(object_depot *, void *));
|
||||||
void object_depot_destroy(object_depot *depot);
|
void object_depot_destroy(object_depot *depot);
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ extern "C" {
|
|||||||
|
|
||||||
// startup only
|
// startup only
|
||||||
status_t vm_init(kernel_args *args);
|
status_t vm_init(kernel_args *args);
|
||||||
status_t slab_init();
|
|
||||||
status_t vm_init_post_sem(struct kernel_args *args);
|
status_t vm_init_post_sem(struct kernel_args *args);
|
||||||
status_t vm_init_post_thread(struct kernel_args *args);
|
status_t vm_init_post_thread(struct kernel_args *args);
|
||||||
status_t vm_init_post_modules(struct kernel_args *args);
|
status_t vm_init_post_modules(struct kernel_args *args);
|
||||||
@@ -32,6 +31,10 @@ void vm_free_unused_boot_loader_range(addr_t start, addr_t end);
|
|||||||
addr_t vm_allocate_early(kernel_args *args, size_t virtualSize,
|
addr_t vm_allocate_early(kernel_args *args, size_t virtualSize,
|
||||||
size_t physicalSize, uint32 attributes);
|
size_t physicalSize, uint32 attributes);
|
||||||
|
|
||||||
|
|
||||||
|
void slab_init(addr_t initialBase, size_t initialSize);
|
||||||
|
void slab_init_post_sem();
|
||||||
|
|
||||||
// to protect code regions with interrupts turned on
|
// to protect code regions with interrupts turned on
|
||||||
void permit_page_faults(void);
|
void permit_page_faults(void);
|
||||||
void forbid_page_faults(void);
|
void forbid_page_faults(void);
|
||||||
|
|||||||
@@ -137,8 +137,6 @@ _start(kernel_args *bootKernelArgs, int currentCPU)
|
|||||||
generic_syscall_init();
|
generic_syscall_init();
|
||||||
TRACE("init cbuf\n");
|
TRACE("init cbuf\n");
|
||||||
cbuf_init();
|
cbuf_init();
|
||||||
TRACE("init slab\n");
|
|
||||||
slab_init();
|
|
||||||
TRACE("init teams\n");
|
TRACE("init teams\n");
|
||||||
team_init(&sKernelArgs);
|
team_init(&sKernelArgs);
|
||||||
TRACE("init threads\n");
|
TRACE("init threads\n");
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ SubDir HAIKU_TOP src system kernel slab ;
|
|||||||
UsePrivateHeaders [ FDirName kernel slab ] ;
|
UsePrivateHeaders [ FDirName kernel slab ] ;
|
||||||
|
|
||||||
KernelMergeObject kernel_slab.o :
|
KernelMergeObject kernel_slab.o :
|
||||||
|
allocator.cpp
|
||||||
Slab.cpp
|
Slab.cpp
|
||||||
|
|
||||||
: $(TARGET_KERNEL_PIC_CCFLAGS) -Wno-unused
|
: $(TARGET_KERNEL_PIC_CCFLAGS) -Wno-unused
|
||||||
|
|||||||
+183
-51
@@ -8,6 +8,9 @@
|
|||||||
|
|
||||||
#include <Slab.h>
|
#include <Slab.h>
|
||||||
|
|
||||||
|
#include "slab_private.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
@@ -16,6 +19,7 @@
|
|||||||
#include <util/OpenHashTable.h>
|
#include <util/OpenHashTable.h>
|
||||||
|
|
||||||
#include <smp.h>
|
#include <smp.h>
|
||||||
|
#include <vm.h>
|
||||||
#include <vm_low_memory.h>
|
#include <vm_low_memory.h>
|
||||||
|
|
||||||
#include <algorithm> // swap
|
#include <algorithm> // swap
|
||||||
@@ -39,9 +43,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
extern "C" status_t slab_init();
|
|
||||||
|
|
||||||
|
|
||||||
static const int kMagazineCapacity = 32;
|
static const int kMagazineCapacity = 32;
|
||||||
static const size_t kCacheColorPeriod = 8;
|
static const size_t kCacheColorPeriod = 8;
|
||||||
|
|
||||||
@@ -155,11 +156,13 @@ struct depot_cpu_store {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static object_cache *sSlabCache, *sLinkCache;
|
|
||||||
static ObjectCacheList sObjectCaches;
|
static ObjectCacheList sObjectCaches;
|
||||||
static benaphore sObjectCacheListLock;
|
static benaphore sObjectCacheListLock;
|
||||||
|
|
||||||
|
static uint8 *sInitialBegin, *sInitialLimit, *sInitialPointer;
|
||||||
|
|
||||||
|
|
||||||
|
static status_t object_depot_init_locks(object_depot *depot);
|
||||||
static depot_magazine *alloc_magazine();
|
static depot_magazine *alloc_magazine();
|
||||||
static void free_magazine(depot_magazine *magazine);
|
static void free_magazine(depot_magazine *magazine);
|
||||||
|
|
||||||
@@ -215,13 +218,57 @@ __fls0(size_t value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void *
|
||||||
|
internal_alloc(size_t size, uint32 flags)
|
||||||
|
{
|
||||||
|
if (flags & CACHE_DURING_BOOT) {
|
||||||
|
if ((sInitialPointer + size) > sInitialLimit)
|
||||||
|
panic("internal_alloc: ran out of initial space");
|
||||||
|
|
||||||
|
uint8 *buffer = sInitialPointer;
|
||||||
|
sInitialPointer += size;
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
return block_alloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
internal_free(void *_buffer)
|
||||||
|
{
|
||||||
|
uint8 *buffer = (uint8 *)_buffer;
|
||||||
|
|
||||||
|
if (buffer >= sInitialBegin && buffer < sInitialLimit)
|
||||||
|
return;
|
||||||
|
|
||||||
|
block_free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
benaphore_boot_init(benaphore *lock, const char *name, uint32 flags)
|
||||||
|
{
|
||||||
|
if (flags & CACHE_DURING_BOOT) {
|
||||||
|
lock->sem = -1;
|
||||||
|
lock->count = 0;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return benaphore_init(lock, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
allocate_pages(object_cache *cache, void **pages, uint32 flags)
|
allocate_pages(object_cache *cache, void **pages, uint32 flags)
|
||||||
{
|
{
|
||||||
TRACE_CACHE(cache, "allocate pages (%lu, 0x0%lx)", cache->slab_size, flags);
|
TRACE_CACHE(cache, "allocate pages (%lu, 0x0%lx)", cache->slab_size, flags);
|
||||||
|
|
||||||
|
// if we are allocating, it is because we need the pages immediatly
|
||||||
|
// so we lock them. when moving the slab to the empty list we should
|
||||||
|
// unlock them, and lock them again when getting one from the empty list.
|
||||||
area_id areaId = create_area(cache->name, pages, B_ANY_KERNEL_ADDRESS,
|
area_id areaId = create_area(cache->name, pages, B_ANY_KERNEL_ADDRESS,
|
||||||
cache->slab_size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
|
cache->slab_size, B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA);
|
||||||
if (areaId < 0)
|
if (areaId < 0)
|
||||||
return areaId;
|
return areaId;
|
||||||
|
|
||||||
@@ -314,12 +361,12 @@ object_cache_init(object_cache *cache, const char *name, size_t objectSize,
|
|||||||
object_cache_constructor constructor, object_cache_destructor destructor,
|
object_cache_constructor constructor, object_cache_destructor destructor,
|
||||||
object_cache_reclaimer reclaimer)
|
object_cache_reclaimer reclaimer)
|
||||||
{
|
{
|
||||||
status_t status = benaphore_init(&cache->lock, name);
|
strlcpy(cache->name, name, sizeof(cache->name));
|
||||||
|
|
||||||
|
status_t status = benaphore_boot_init(&cache->lock, name, flags);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
strlcpy(cache->name, name, sizeof(cache->name));
|
|
||||||
|
|
||||||
if (objectSize < sizeof(object_link))
|
if (objectSize < sizeof(object_link))
|
||||||
objectSize = sizeof(object_link);
|
objectSize = sizeof(object_link);
|
||||||
|
|
||||||
@@ -347,7 +394,7 @@ object_cache_init(object_cache *cache, const char *name, size_t objectSize,
|
|||||||
cache->flags |= CACHE_NO_DEPOT;
|
cache->flags |= CACHE_NO_DEPOT;
|
||||||
|
|
||||||
if (!(cache->flags & CACHE_NO_DEPOT)) {
|
if (!(cache->flags & CACHE_NO_DEPOT)) {
|
||||||
status_t status = object_depot_init(&cache->depot,
|
status_t status = object_depot_init(&cache->depot, flags,
|
||||||
object_cache_return_object_wrapper);
|
object_cache_return_object_wrapper);
|
||||||
if (status < B_OK) {
|
if (status < B_OK) {
|
||||||
benaphore_destroy(&cache->lock);
|
benaphore_destroy(&cache->lock);
|
||||||
@@ -369,19 +416,43 @@ object_cache_init(object_cache *cache, const char *name, size_t objectSize,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
object_cache_init_locks(object_cache *cache)
|
||||||
|
{
|
||||||
|
status_t status = benaphore_init(&cache->lock, cache->name);
|
||||||
|
if (status < B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
if (cache->flags & CACHE_NO_DEPOT)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
return object_depot_init_locks(&cache->depot);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_cache(object_cache *cache)
|
||||||
|
{
|
||||||
|
cache->~object_cache();
|
||||||
|
internal_free(cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static SmallObjectCache *
|
static SmallObjectCache *
|
||||||
create_small_object_cache(const char *name, size_t object_size,
|
create_small_object_cache(const char *name, size_t object_size,
|
||||||
size_t alignment, size_t maximum, uint32 flags, void *cookie,
|
size_t alignment, size_t maximum, uint32 flags, void *cookie,
|
||||||
object_cache_constructor constructor, object_cache_destructor destructor,
|
object_cache_constructor constructor, object_cache_destructor destructor,
|
||||||
object_cache_reclaimer reclaimer)
|
object_cache_reclaimer reclaimer)
|
||||||
{
|
{
|
||||||
SmallObjectCache *cache = new (std::nothrow) SmallObjectCache();
|
void *buffer = internal_alloc(sizeof(SmallObjectCache), flags);
|
||||||
if (cache == NULL)
|
if (buffer == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
SmallObjectCache *cache = new (buffer) SmallObjectCache();
|
||||||
|
|
||||||
if (object_cache_init(cache, name, object_size, alignment, maximum, flags,
|
if (object_cache_init(cache, name, object_size, alignment, maximum, flags,
|
||||||
cookie, constructor, destructor, reclaimer) < B_OK) {
|
cookie, constructor, destructor, reclaimer) < B_OK) {
|
||||||
delete cache;
|
delete_cache(cache);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -397,13 +468,15 @@ create_hashed_object_cache(const char *name, size_t object_size,
|
|||||||
object_cache_constructor constructor, object_cache_destructor destructor,
|
object_cache_constructor constructor, object_cache_destructor destructor,
|
||||||
object_cache_reclaimer reclaimer)
|
object_cache_reclaimer reclaimer)
|
||||||
{
|
{
|
||||||
HashedObjectCache *cache = new (std::nothrow) HashedObjectCache();
|
void *buffer = internal_alloc(sizeof(HashedObjectCache), flags);
|
||||||
if (cache == NULL)
|
if (buffer == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
HashedObjectCache *cache = new (buffer) HashedObjectCache();
|
||||||
|
|
||||||
if (object_cache_init(cache, name, object_size, alignment, maximum, flags,
|
if (object_cache_init(cache, name, object_size, alignment, maximum, flags,
|
||||||
cookie, constructor, destructor, reclaimer) < B_OK) {
|
cookie, constructor, destructor, reclaimer) < B_OK) {
|
||||||
delete cache;
|
delete_cache(cache);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,7 +539,7 @@ delete_object_cache(object_cache *cache)
|
|||||||
cache->ReturnSlab(cache->empty.RemoveHead());
|
cache->ReturnSlab(cache->empty.RemoveHead());
|
||||||
|
|
||||||
benaphore_destroy(&cache->lock);
|
benaphore_destroy(&cache->lock);
|
||||||
delete cache;
|
delete_cache(cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -504,8 +577,8 @@ object_cache_alloc(object_cache *cache, uint32 flags)
|
|||||||
source->count--;
|
source->count--;
|
||||||
cache->used_count++;
|
cache->used_count++;
|
||||||
|
|
||||||
TRACE_CACHE(cache, "allocate %p from %p, %lu remaining.", link, source,
|
TRACE_CACHE(cache, "allocate %p (%p) from %p, %lu remaining.",
|
||||||
source->count);
|
link_to_object(link, cache->object_size), link, source, source->count);
|
||||||
|
|
||||||
if (source->count == 0) {
|
if (source->count == 0) {
|
||||||
cache->partial.Remove(source);
|
cache->partial.Remove(source);
|
||||||
@@ -524,8 +597,9 @@ object_cache_return_to_slab(object_cache *cache, slab *source, void *object)
|
|||||||
|
|
||||||
object_link *link = object_to_link(object, cache->object_size);
|
object_link *link = object_to_link(object, cache->object_size);
|
||||||
|
|
||||||
TRACE_CACHE(cache, "returning %p to %p, %lu used (%lu empty slabs).",
|
TRACE_CACHE(cache, "returning %p (%p) to %p, %lu used (%lu empty slabs).",
|
||||||
link, source, source->size - source->count, cache->empty_count);
|
object, link, source, source->size - source->count,
|
||||||
|
cache->empty_count);
|
||||||
|
|
||||||
_push(source->free, link);
|
_push(source->free, link);
|
||||||
source->count++;
|
source->count++;
|
||||||
@@ -693,28 +767,29 @@ SmallObjectCache::ObjectSlab(void *object) const
|
|||||||
static slab *
|
static slab *
|
||||||
allocate_slab(uint32 flags)
|
allocate_slab(uint32 flags)
|
||||||
{
|
{
|
||||||
return (slab *)object_cache_alloc(sSlabCache, flags);
|
return (slab *)internal_alloc(sizeof(slab), flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
free_slab(slab *slab)
|
free_slab(slab *slab)
|
||||||
{
|
{
|
||||||
object_cache_free(sSlabCache, slab);
|
internal_free(slab);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static HashedObjectCache::Link *
|
static HashedObjectCache::Link *
|
||||||
allocate_link(uint32 flags)
|
allocate_link(uint32 flags)
|
||||||
{
|
{
|
||||||
return (HashedObjectCache::Link *)object_cache_alloc(sLinkCache, flags);
|
return (HashedObjectCache::Link *)
|
||||||
|
internal_alloc(sizeof(HashedObjectCache::Link), flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
free_link(HashedObjectCache::Link *link)
|
free_link(HashedObjectCache::Link *link)
|
||||||
{
|
{
|
||||||
object_cache_free(sLinkCache, link);
|
internal_free(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -863,8 +938,8 @@ exchange_with_empty(object_depot *depot, depot_magazine* &magazine)
|
|||||||
static depot_magazine *
|
static depot_magazine *
|
||||||
alloc_magazine()
|
alloc_magazine()
|
||||||
{
|
{
|
||||||
depot_magazine *magazine = (depot_magazine *)malloc(sizeof(depot_magazine)
|
depot_magazine *magazine = (depot_magazine *)internal_alloc(
|
||||||
+ kMagazineCapacity * sizeof(void *));
|
sizeof(depot_magazine) + kMagazineCapacity * sizeof(void *), 0);
|
||||||
if (magazine) {
|
if (magazine) {
|
||||||
magazine->next = NULL;
|
magazine->next = NULL;
|
||||||
magazine->current_round = 0;
|
magazine->current_round = 0;
|
||||||
@@ -878,7 +953,7 @@ alloc_magazine()
|
|||||||
static void
|
static void
|
||||||
free_magazine(depot_magazine *magazine)
|
free_magazine(depot_magazine *magazine)
|
||||||
{
|
{
|
||||||
free(magazine);
|
internal_free(magazine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -892,25 +967,26 @@ empty_magazine(object_depot *depot, depot_magazine *magazine)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
object_depot_init(object_depot *depot,
|
object_depot_init(object_depot *depot, uint32 flags,
|
||||||
void (*return_object)(object_depot *depot, void *object))
|
void (*return_object)(object_depot *depot, void *object))
|
||||||
{
|
{
|
||||||
depot->full = NULL;
|
depot->full = NULL;
|
||||||
depot->empty = NULL;
|
depot->empty = NULL;
|
||||||
depot->full_count = depot->empty_count = 0;
|
depot->full_count = depot->empty_count = 0;
|
||||||
|
|
||||||
status_t status = benaphore_init(&depot->lock, "depot");
|
status_t status = benaphore_boot_init(&depot->lock, "depot", flags);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
depot->stores = new (std::nothrow) depot_cpu_store[smp_get_num_cpus()];
|
depot->stores = (depot_cpu_store *)internal_alloc(sizeof(depot_cpu_store)
|
||||||
|
* smp_get_num_cpus(), flags);
|
||||||
if (depot->stores == NULL) {
|
if (depot->stores == NULL) {
|
||||||
benaphore_destroy(&depot->lock);
|
benaphore_destroy(&depot->lock);
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < smp_get_num_cpus(); i++) {
|
for (int i = 0; i < smp_get_num_cpus(); i++) {
|
||||||
benaphore_init(&depot->stores[i].lock, "cpu store");
|
benaphore_boot_init(&depot->stores[i].lock, "cpu store", flags);
|
||||||
depot->stores[i].loaded = depot->stores[i].previous = NULL;
|
depot->stores[i].loaded = depot->stores[i].previous = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -920,6 +996,23 @@ object_depot_init(object_depot *depot,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
object_depot_init_locks(object_depot *depot)
|
||||||
|
{
|
||||||
|
status_t status = benaphore_init(&depot->lock, "depot");
|
||||||
|
if (status < B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
for (int i = 0; i < smp_get_num_cpus(); i++) {
|
||||||
|
status = benaphore_init(&depot->stores[i].lock, "cpu store");
|
||||||
|
if (status < B_OK)
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
object_depot_destroy(object_depot *depot)
|
object_depot_destroy(object_depot *depot)
|
||||||
{
|
{
|
||||||
@@ -929,7 +1022,7 @@ object_depot_destroy(object_depot *depot)
|
|||||||
benaphore_destroy(&depot->stores[i].lock);
|
benaphore_destroy(&depot->stores[i].lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete [] depot->stores;
|
internal_free(depot->stores);
|
||||||
|
|
||||||
benaphore_destroy(&depot->lock);
|
benaphore_destroy(&depot->lock);
|
||||||
}
|
}
|
||||||
@@ -1030,44 +1123,83 @@ object_depot_make_empty(object_depot *depot)
|
|||||||
static int
|
static int
|
||||||
dump_slabs(int argc, char *argv[])
|
dump_slabs(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
kprintf("%10s %32s %8s %8s %6s %8s %6s\n", "address", "name", "objsize", "usage",
|
kprintf("%10s %22s %8s %8s %6s %8s %8s %8s\n", "address", "name",
|
||||||
"empty", "usedobj", "flags");
|
"objsize", "usage", "empty", "usedobj", "total", "flags");
|
||||||
|
|
||||||
ObjectCacheList::Iterator it = sObjectCaches.GetIterator();
|
ObjectCacheList::Iterator it = sObjectCaches.GetIterator();
|
||||||
|
|
||||||
while (it.HasNext()) {
|
while (it.HasNext()) {
|
||||||
object_cache *cache = it.Next();
|
object_cache *cache = it.Next();
|
||||||
|
|
||||||
kprintf("%p %32s %8lu %8lu %6lu %8lu %6lx\n", cache, cache->name,
|
kprintf("%p %22s %8lu %8lu %6lu %8lu %8lu %8lx\n", cache, cache->name,
|
||||||
cache->object_size, cache->usage, cache->empty_count,
|
cache->object_size, cache->usage, cache->empty_count,
|
||||||
cache->used_count, cache->flags);
|
cache->used_count, cache->usage / cache->object_size,
|
||||||
|
cache->flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
static int
|
||||||
slab_init()
|
dump_cache_info(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
if (argc < 2) {
|
||||||
|
kprintf("usage: cache_info [address]\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
object_cache *cache = (object_cache *)strtoul(argv[1], NULL, 16);
|
||||||
|
|
||||||
|
kprintf("name: %s\n", cache->name);
|
||||||
|
kprintf("lock: { count: %i, sem: %ld }\n", cache->lock.count,
|
||||||
|
cache->lock.sem);
|
||||||
|
kprintf("object_size: %lu\n", cache->object_size);
|
||||||
|
kprintf("cache_color_cycle: %lu\n", cache->cache_color_cycle);
|
||||||
|
kprintf("used_count: %lu\n", cache->used_count);
|
||||||
|
kprintf("empty_count: %lu\n", cache->empty_count);
|
||||||
|
kprintf("pressure: %lu\n", cache->pressure);
|
||||||
|
kprintf("slab_size: %lu\n", cache->slab_size);
|
||||||
|
kprintf("usage: %lu\n", cache->usage);
|
||||||
|
kprintf("maximum: %lu\n", cache->maximum);
|
||||||
|
kprintf("flags: 0x%lx\n", cache->flags);
|
||||||
|
kprintf("cookie: %p\n", cache->cookie);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
slab_init(addr_t initialBase, size_t initialSize)
|
||||||
|
{
|
||||||
|
sInitialBegin = (uint8 *)initialBase;
|
||||||
|
sInitialLimit = sInitialBegin + initialSize;
|
||||||
|
sInitialPointer = sInitialBegin;
|
||||||
|
|
||||||
|
new (&sObjectCaches) ObjectCacheList();
|
||||||
|
|
||||||
|
block_allocator_init_boot();
|
||||||
|
|
||||||
|
add_debugger_command("slabs", dump_slabs, "list all object caches");
|
||||||
|
add_debugger_command("cache_info", dump_cache_info,
|
||||||
|
"dump information about a specific cache");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
slab_init_post_sem()
|
||||||
{
|
{
|
||||||
status_t status = benaphore_init(&sObjectCacheListLock, "object cache list");
|
status_t status = benaphore_init(&sObjectCacheListLock, "object cache list");
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
panic("slab_init: failed to create object cache list lock");
|
panic("slab_init: failed to create object cache list lock");
|
||||||
|
|
||||||
new (&sObjectCaches) ObjectCacheList();
|
ObjectCacheList::Iterator it = sObjectCaches.GetIterator();
|
||||||
|
|
||||||
sSlabCache = create_object_cache("slab cache", sizeof(slab), 4, NULL, NULL,
|
while (it.HasNext()) {
|
||||||
NULL);
|
if (object_cache_init_locks(it.Next()) < B_OK)
|
||||||
if (sSlabCache == NULL)
|
panic("slab_init: failed to create sems");
|
||||||
panic("slab_init: failed to create slab cache");
|
}
|
||||||
|
|
||||||
sLinkCache = create_object_cache("link cache",
|
block_allocator_init_rest();
|
||||||
sizeof(HashedObjectCache::Link), 4, NULL, NULL, NULL);
|
|
||||||
if (sLinkCache == NULL)
|
|
||||||
panic("slab_init: failed to create link cache");
|
|
||||||
|
|
||||||
add_debugger_command("slabs", dump_slabs, "list all object caches");
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2007, Hugo Santos. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Hugo Santos, [email protected]
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Slab.h>
|
||||||
|
|
||||||
|
#include "slab_private.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define DEBUG_ALLOCATOR
|
||||||
|
|
||||||
|
static const size_t kBlockSizes[] = {
|
||||||
|
16, 24, 32, 48, 64, 80, 96, 112,
|
||||||
|
128, 160, 192, 224, 256, 320, 384, 448,
|
||||||
|
512, 640, 768, 896, 1024, 1280, 1536, 1792,
|
||||||
|
2048, 2560, 3072, 3584, 4096, 4608, 5120, 5632,
|
||||||
|
6144, 6656, 7168, 7680, 8192,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
static object_cache *sBlockCaches[sizeof(kBlockSizes) / sizeof(size_t)];
|
||||||
|
|
||||||
|
struct boundary_tag {
|
||||||
|
uint32 size;
|
||||||
|
#ifdef DEBUG_ALLOCATOR
|
||||||
|
uint32 magic;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32 kBoundaryMagic = 0x6da78d13;
|
||||||
|
|
||||||
|
|
||||||
|
static object_cache *
|
||||||
|
size_to_cache(size_t size)
|
||||||
|
{
|
||||||
|
if (size <= 128)
|
||||||
|
return sBlockCaches[size / 16];
|
||||||
|
else if (size <= 256)
|
||||||
|
return sBlockCaches[8 + (size - 128) / 32];
|
||||||
|
else if (size <= 512)
|
||||||
|
return sBlockCaches[12 + (size - 256) / 64];
|
||||||
|
else if (size <= 1024)
|
||||||
|
return sBlockCaches[16 + (size - 512) / 128];
|
||||||
|
else if (size <= 2048)
|
||||||
|
return sBlockCaches[20 + (size - 1024) / 256];
|
||||||
|
else if (size <= 8192)
|
||||||
|
return sBlockCaches[24 + (size - 2048) / 512];
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *
|
||||||
|
block_alloc(size_t size)
|
||||||
|
{
|
||||||
|
object_cache *cache = size_to_cache(size + sizeof(boundary_tag));
|
||||||
|
|
||||||
|
void *block;
|
||||||
|
|
||||||
|
if (cache) {
|
||||||
|
block = object_cache_alloc(cache, 0);
|
||||||
|
} else {
|
||||||
|
// TODO create areas
|
||||||
|
panic("allocator: unimplemented");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
boundary_tag *tag = (boundary_tag *)block;
|
||||||
|
|
||||||
|
tag->size = size;
|
||||||
|
|
||||||
|
#ifdef DEBUG_ALLOCATOR
|
||||||
|
tag->magic = kBoundaryMagic;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ((uint8 *)block) + sizeof(boundary_tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
block_free(void *block)
|
||||||
|
{
|
||||||
|
boundary_tag *tag = (boundary_tag *)(((uint8 *)block)
|
||||||
|
- sizeof(boundary_tag));
|
||||||
|
|
||||||
|
#ifdef DEBUG_ALLOCATOR
|
||||||
|
if (tag->magic != kBoundaryMagic)
|
||||||
|
panic("allocator: boundary tag magic doesn't match this universe");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
object_cache *cache = size_to_cache(tag->size);
|
||||||
|
if (cache == NULL)
|
||||||
|
panic("allocator: unimplemented");
|
||||||
|
|
||||||
|
object_cache_free(cache, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
block_create_cache(size_t index, bool boot)
|
||||||
|
{
|
||||||
|
char name[32];
|
||||||
|
snprintf(name, sizeof(name), "block cache: %lu", kBlockSizes[index]);
|
||||||
|
|
||||||
|
sBlockCaches[index] = create_object_cache_etc(name, kBlockSizes[index],
|
||||||
|
0, 0, boot ? CACHE_DURING_BOOT : 0, NULL, NULL, NULL, NULL);
|
||||||
|
if (sBlockCaches[index] == NULL)
|
||||||
|
panic("allocator: failed to init block cache");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
block_allocator_init_boot()
|
||||||
|
{
|
||||||
|
for (int index = 0; kBlockSizes[index] != 0; index++) {
|
||||||
|
if (kBlockSizes[index] > 256)
|
||||||
|
break;
|
||||||
|
|
||||||
|
block_create_cache(index, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
block_allocator_init_rest()
|
||||||
|
{
|
||||||
|
for (int index = 0; kBlockSizes[index] != 0; index++) {
|
||||||
|
if (kBlockSizes[index] <= 256)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
block_create_cache(index, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2007, Hugo Santos. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Hugo Santos, [email protected]
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _SLAB_PRIVATE_H_
|
||||||
|
#define _SLAB_PRIVATE_H_
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
void *block_alloc(size_t size);
|
||||||
|
void block_free(void *block);
|
||||||
|
void block_allocator_init_boot();
|
||||||
|
void block_allocator_init_rest();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -2891,6 +2891,11 @@ vm_init(kernel_args *args)
|
|||||||
TRACE(("heap at 0x%lx\n", heapBase));
|
TRACE(("heap at 0x%lx\n", heapBase));
|
||||||
heap_init(heapBase, heapSize);
|
heap_init(heapBase, heapSize);
|
||||||
|
|
||||||
|
size_t slabInitialSize = 2 * B_PAGE_SIZE;
|
||||||
|
addr_t slabInitialBase = vm_allocate_early(args, slabInitialSize,
|
||||||
|
slabInitialSize, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||||
|
slab_init(slabInitialBase, slabInitialSize);
|
||||||
|
|
||||||
// initialize the free page list and physical page mapper
|
// initialize the free page list and physical page mapper
|
||||||
vm_page_init(args);
|
vm_page_init(args);
|
||||||
|
|
||||||
@@ -2919,6 +2924,11 @@ vm_init(kernel_args *args)
|
|||||||
create_area("kernel heap", &address, B_EXACT_ADDRESS, heapSize,
|
create_area("kernel heap", &address, B_EXACT_ADDRESS, heapSize,
|
||||||
B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||||
|
|
||||||
|
address = (void *)ROUNDOWN(slabInitialBase, B_PAGE_SIZE);
|
||||||
|
create_area("initial slab space", &address, B_EXACT_ADDRESS,
|
||||||
|
slabInitialSize, B_ALREADY_WIRED, B_KERNEL_READ_AREA
|
||||||
|
| B_KERNEL_WRITE_AREA);
|
||||||
|
|
||||||
allocate_kernel_args(args);
|
allocate_kernel_args(args);
|
||||||
|
|
||||||
args->kernel_image.name = "kernel";
|
args->kernel_image.name = "kernel";
|
||||||
@@ -2985,6 +2995,8 @@ vm_init_post_sem(kernel_args *args)
|
|||||||
|
|
||||||
sAreaHashLock = create_sem(WRITE_COUNT, "area hash");
|
sAreaHashLock = create_sem(WRITE_COUNT, "area hash");
|
||||||
|
|
||||||
|
slab_init_post_sem();
|
||||||
|
|
||||||
return heap_init_post_sem(args);
|
return heap_init_post_sem(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user