2007-04-26 03:41:24 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2007, Hugo Santos. All Rights Reserved.
|
|
|
|
* Distributed under the terms of the MIT License.
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Hugo Santos, hugosantos@gmail.com
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _SLAB_BASE_SLAB_H_
|
|
|
|
#define _SLAB_BASE_SLAB_H_
|
|
|
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
2007-04-26 07:31:19 +00:00
|
|
|
#include <KernelExport.h>
|
2007-04-26 03:41:24 +00:00
|
|
|
#include <OS.h>
|
2007-04-26 07:31:19 +00:00
|
|
|
|
|
|
|
#include <lock.h>
|
|
|
|
#include <vm_low_memory.h>
|
|
|
|
#include <util/AutoLock.h>
|
2007-04-26 03:41:24 +00:00
|
|
|
#include <util/list.h>
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
#include <utility> // pair<>
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
2007-04-26 06:32:25 +00:00
|
|
|
enum {
|
|
|
|
CACHE_DONT_SLEEP = 1 << 0,
|
|
|
|
CACHE_ALIGN_TO_TOTAL = 1 << 16,
|
|
|
|
};
|
|
|
|
|
2007-04-26 03:41:24 +00:00
|
|
|
static const int kMinimumSlabItems = 32;
|
|
|
|
|
2007-04-26 11:38:24 +00:00
|
|
|
typedef status_t (*base_cache_constructor)(void *cookie, void *object);
|
2007-04-26 03:41:24 +00:00
|
|
|
typedef void (*base_cache_destructor)(void *cookie, void *object);
|
|
|
|
|
2007-04-26 06:05:08 +00:00
|
|
|
/* base Slab implementation, opaque to the backend used.
|
|
|
|
*
|
2007-04-26 07:31:19 +00:00
|
|
|
* NOTE: the caller is responsible for the Cache's locking.
|
|
|
|
* Cache<> below handles it as well. */
|
2007-04-26 03:41:24 +00:00
|
|
|
|
|
|
|
typedef struct base_cache {
|
|
|
|
char name[32];
|
|
|
|
size_t object_size;
|
|
|
|
size_t cache_color_cycle;
|
2007-04-26 06:05:08 +00:00
|
|
|
struct list empty, partial, full;
|
2007-04-26 07:31:19 +00:00
|
|
|
size_t empty_count, pressure;
|
2007-04-26 03:41:24 +00:00
|
|
|
base_cache_constructor constructor;
|
|
|
|
base_cache_destructor destructor;
|
|
|
|
void *cookie;
|
|
|
|
} base_cache;
|
|
|
|
|
|
|
|
typedef struct cache_object_link {
|
|
|
|
struct cache_object_link *next;
|
|
|
|
} cache_object_link;
|
|
|
|
|
|
|
|
typedef struct cache_slab {
|
|
|
|
void *pages;
|
|
|
|
size_t count, size;
|
2007-04-26 15:40:53 +00:00
|
|
|
size_t offset;
|
2007-04-26 03:41:24 +00:00
|
|
|
cache_object_link *free;
|
|
|
|
struct list_link link;
|
|
|
|
} cache_slab;
|
|
|
|
|
2007-04-26 07:31:19 +00:00
|
|
|
// TODO add reclaim method to base_cache to be called under severe memory
|
|
|
|
// pressure so the slab owner can free as much buffers as possible.
|
|
|
|
|
2007-04-26 03:41:24 +00:00
|
|
|
void base_cache_init(base_cache *cache, const char *name, size_t object_size,
|
|
|
|
size_t alignment, base_cache_constructor constructor,
|
|
|
|
base_cache_destructor destructor, void *cookie);
|
2007-04-26 06:05:08 +00:00
|
|
|
void base_cache_destroy(base_cache *cache,
|
|
|
|
void (*return_slab)(base_cache *, cache_slab *));
|
2007-04-26 07:31:19 +00:00
|
|
|
void base_cache_low_memory(base_cache *cache, int32 level,
|
|
|
|
void (*return_slab)(base_cache *, cache_slab *));
|
2007-04-26 03:41:24 +00:00
|
|
|
|
2007-04-26 15:40:53 +00:00
|
|
|
void *base_cache_allocate_object(base_cache *cache);
|
|
|
|
void *base_cache_allocate_object_with_new_slab(base_cache *cache,
|
2007-04-26 06:05:08 +00:00
|
|
|
cache_slab *slab);
|
2007-04-26 03:41:24 +00:00
|
|
|
int base_cache_return_object(base_cache *cache, cache_slab *slab,
|
2007-04-26 15:40:53 +00:00
|
|
|
void *object);
|
2007-04-26 03:41:24 +00:00
|
|
|
|
2007-04-26 11:38:24 +00:00
|
|
|
typedef status_t (*base_cache_owner_prepare)(void *parent,
|
|
|
|
cache_slab *slab, void *object);
|
|
|
|
typedef void (*base_cache_owner_unprepare)(void *parent, cache_slab *slab,
|
|
|
|
void *object);
|
|
|
|
|
2007-04-26 03:41:24 +00:00
|
|
|
cache_slab *base_cache_construct_slab(base_cache *cache, cache_slab *slab,
|
2007-04-26 11:38:24 +00:00
|
|
|
void *pages, size_t byte_count, void *parent,
|
|
|
|
base_cache_owner_prepare prepare, base_cache_owner_unprepare unprepare);
|
2007-04-26 15:40:53 +00:00
|
|
|
void base_cache_destruct_slab(base_cache *cache, cache_slab *slab,
|
|
|
|
void *parent, base_cache_owner_unprepare unprepare);
|
2007-04-26 03:41:24 +00:00
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
|
|
|
|
// Slab implementation, glues together the frontend, backend as
|
|
|
|
// well as the Slab strategy used.
|
|
|
|
template<typename Strategy>
|
|
|
|
class Cache : protected base_cache {
|
|
|
|
public:
|
2007-04-26 07:31:19 +00:00
|
|
|
typedef Cache<Strategy> ThisCache;
|
2007-04-26 03:41:24 +00:00
|
|
|
typedef base_cache_constructor Constructor;
|
|
|
|
typedef base_cache_destructor Destructor;
|
|
|
|
|
|
|
|
Cache(const char *name, size_t objectSize, size_t alignment,
|
|
|
|
Constructor constructor, Destructor destructor, void *cookie)
|
|
|
|
: fStrategy(this)
|
|
|
|
{
|
2007-04-26 07:31:19 +00:00
|
|
|
if (benaphore_init(&fLock, name) >= B_OK) {
|
2007-04-26 15:40:53 +00:00
|
|
|
base_cache_init(this, name, objectSize, alignment, constructor,
|
|
|
|
destructor, cookie);
|
2007-04-26 07:31:19 +00:00
|
|
|
register_low_memory_handler(_LowMemory, this, 0);
|
|
|
|
}
|
2007-04-26 03:41:24 +00:00
|
|
|
}
|
|
|
|
|
2007-04-26 06:05:08 +00:00
|
|
|
~Cache()
|
|
|
|
{
|
2007-04-26 07:31:19 +00:00
|
|
|
if (fLock.sem >= B_OK) {
|
|
|
|
benaphore_lock(&fLock);
|
|
|
|
unregister_low_memory_handler(_LowMemory, this);
|
|
|
|
base_cache_destroy(this, _ReturnSlab);
|
|
|
|
benaphore_destroy(&fLock);
|
|
|
|
}
|
2007-04-26 06:05:08 +00:00
|
|
|
}
|
|
|
|
|
2007-04-26 07:31:19 +00:00
|
|
|
status_t InitCheck() const { return fLock.sem; }
|
|
|
|
|
2007-04-26 03:41:24 +00:00
|
|
|
void *AllocateObject(uint32_t flags)
|
|
|
|
{
|
2007-04-26 07:31:19 +00:00
|
|
|
BenaphoreLocker _(fLock);
|
|
|
|
|
2007-04-26 15:40:53 +00:00
|
|
|
void *object = base_cache_allocate_object(this);
|
2007-04-26 06:05:08 +00:00
|
|
|
|
|
|
|
// if the cache is returning NULL it is because it ran out of slabs
|
2007-04-26 15:40:53 +00:00
|
|
|
if (object == NULL) {
|
2007-04-26 03:41:24 +00:00
|
|
|
cache_slab *newSlab = fStrategy.NewSlab(flags);
|
|
|
|
if (newSlab == NULL)
|
|
|
|
return NULL;
|
2007-04-26 15:40:53 +00:00
|
|
|
object = base_cache_allocate_object_with_new_slab(this, newSlab);
|
|
|
|
if (object == NULL)
|
2007-04-26 06:05:08 +00:00
|
|
|
panic("cache: failed to allocate with an empty slab");
|
2007-04-26 03:41:24 +00:00
|
|
|
}
|
|
|
|
|
2007-04-26 15:40:53 +00:00
|
|
|
return object;
|
2007-04-26 03:41:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ReturnObject(void *object)
|
|
|
|
{
|
2007-04-26 07:31:19 +00:00
|
|
|
BenaphoreLocker _(fLock);
|
|
|
|
|
2007-04-26 15:40:53 +00:00
|
|
|
cache_slab *slab = fStrategy.ObjectSlab(object);
|
2007-04-26 03:41:24 +00:00
|
|
|
|
2007-04-26 15:40:53 +00:00
|
|
|
if (base_cache_return_object(this, slab, object))
|
|
|
|
fStrategy.ReturnSlab(slab);
|
2007-04-26 03:41:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2007-04-26 06:05:08 +00:00
|
|
|
static void _ReturnSlab(base_cache *self, cache_slab *slab)
|
|
|
|
{
|
2007-04-26 07:31:19 +00:00
|
|
|
// Already locked, ~Cache() -> base_cache_destroy -> _ReturnSlab
|
|
|
|
((ThisCache *)self)->fStrategy.ReturnSlab(slab);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void _LowMemory(void *_self, int32 level)
|
|
|
|
{
|
|
|
|
if (level == B_NO_LOW_MEMORY)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ThisCache *self = (ThisCache *)_self;
|
|
|
|
|
|
|
|
BenaphoreLocker _(self->fLock);
|
|
|
|
base_cache_low_memory(self, level, _ReturnSlab);
|
2007-04-26 06:05:08 +00:00
|
|
|
}
|
|
|
|
|
2007-04-26 07:31:19 +00:00
|
|
|
benaphore fLock;
|
2007-04-26 03:41:24 +00:00
|
|
|
Strategy fStrategy;
|
|
|
|
};
|
|
|
|
|
2007-04-26 06:05:08 +00:00
|
|
|
#endif /* __cplusplus */
|
2007-04-26 03:41:24 +00:00
|
|
|
|
|
|
|
#endif
|