kernel/slab: Use FIFO instead of LIFO queueing for the object cache.
This should make use-after-frees more likely to be caught by the standard paranoia facilities (and make them less likely to be exploitable as memory will take longer to be reused.)
This commit is contained in:
@@ -422,6 +422,28 @@ private:
|
|||||||
#endif // SLAB_MEMORY_MANAGER_TRACING
|
#endif // SLAB_MEMORY_MANAGER_TRACING
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - utility methods
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
static inline Type*
|
||||||
|
_pop(Type*& head)
|
||||||
|
{
|
||||||
|
Type* oldHead = head;
|
||||||
|
head = head->next;
|
||||||
|
return oldHead;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
static inline void
|
||||||
|
_push(Type*& head, Type* object)
|
||||||
|
{
|
||||||
|
object->next = head;
|
||||||
|
head = object;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - MemoryManager
|
// #pragma mark - MemoryManager
|
||||||
|
|
||||||
|
|
||||||
@@ -1441,6 +1463,25 @@ MemoryManager::_FreeArea(Area* area, bool areaRemoved, uint32 flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ inline void
|
||||||
|
MemoryManager::_PushFreeArea(Area* area)
|
||||||
|
{
|
||||||
|
_push(sFreeAreas, area);
|
||||||
|
sFreeAreaCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ inline MemoryManager::Area*
|
||||||
|
MemoryManager::_PopFreeArea()
|
||||||
|
{
|
||||||
|
if (sFreeAreaCount == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
sFreeAreaCount--;
|
||||||
|
return _pop(sFreeAreas);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*static*/ status_t
|
/*static*/ status_t
|
||||||
MemoryManager::_MapChunk(VMArea* vmArea, addr_t address, size_t size,
|
MemoryManager::_MapChunk(VMArea* vmArea, addr_t address, size_t size,
|
||||||
size_t reserveAdditionalMemory, uint32 flags)
|
size_t reserveAdditionalMemory, uint32 flags)
|
||||||
|
|||||||
@@ -239,25 +239,6 @@ MemoryManager::MaintenanceNeeded()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*static*/ inline void
|
|
||||||
MemoryManager::_PushFreeArea(Area* area)
|
|
||||||
{
|
|
||||||
_push(sFreeAreas, area);
|
|
||||||
sFreeAreaCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*static*/ inline MemoryManager::Area*
|
|
||||||
MemoryManager::_PopFreeArea()
|
|
||||||
{
|
|
||||||
if (sFreeAreaCount == 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
sFreeAreaCount--;
|
|
||||||
return _pop(sFreeAreas);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*static*/ inline addr_t
|
/*static*/ inline addr_t
|
||||||
MemoryManager::_AreaBaseAddressForAddress(addr_t address)
|
MemoryManager::_AreaBaseAddressForAddress(addr_t address)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ ObjectCache::Init(const char* name, size_t objectSize, size_t alignment,
|
|||||||
|
|
||||||
mutex_init(&lock, this->name);
|
mutex_init(&lock, this->name);
|
||||||
|
|
||||||
if (objectSize < sizeof(object_link))
|
if (objectSize < sizeof(slab_queue_link))
|
||||||
objectSize = sizeof(object_link);
|
objectSize = sizeof(slab_queue_link);
|
||||||
|
|
||||||
if (alignment < kMinObjectAlignment)
|
if (alignment < kMinObjectAlignment)
|
||||||
alignment = kMinObjectAlignment;
|
alignment = kMinObjectAlignment;
|
||||||
@@ -125,7 +125,7 @@ ObjectCache::InitSlab(slab* slab, void* pages, size_t byteCount, uint32 flags)
|
|||||||
|
|
||||||
slab->pages = pages;
|
slab->pages = pages;
|
||||||
slab->count = slab->size = byteCount / object_size;
|
slab->count = slab->size = byteCount / object_size;
|
||||||
slab->free = NULL;
|
slab->free.Init();
|
||||||
|
|
||||||
size_t spareBytes = byteCount - (slab->size * object_size);
|
size_t spareBytes = byteCount - (slab->size * object_size);
|
||||||
|
|
||||||
@@ -142,7 +142,6 @@ ObjectCache::InitSlab(slab* slab, void* pages, size_t byteCount, uint32 flags)
|
|||||||
|
|
||||||
CREATE_PARANOIA_CHECK_SET(slab, "slab");
|
CREATE_PARANOIA_CHECK_SET(slab, "slab");
|
||||||
|
|
||||||
|
|
||||||
for (size_t i = 0; i < slab->size; i++) {
|
for (size_t i = 0; i < slab->size; i++) {
|
||||||
status_t status = B_OK;
|
status_t status = B_OK;
|
||||||
if (constructor)
|
if (constructor)
|
||||||
@@ -157,11 +156,10 @@ ObjectCache::InitSlab(slab* slab, void* pages, size_t byteCount, uint32 flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
DELETE_PARANOIA_CHECK_SET(slab);
|
DELETE_PARANOIA_CHECK_SET(slab);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
_push(slab->free, object_to_link(data, object_size));
|
slab->free.Push(object_to_link(data, object_size));
|
||||||
|
|
||||||
ADD_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, slab,
|
ADD_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, slab,
|
||||||
&object_to_link(data, object_size)->next, sizeof(void*));
|
&object_to_link(data, object_size)->next, sizeof(void*));
|
||||||
@@ -216,13 +214,13 @@ ObjectCache::ReturnObjectToSlab(slab* source, void* object, uint32 flags)
|
|||||||
}
|
}
|
||||||
#endif // KDEBUG
|
#endif // KDEBUG
|
||||||
|
|
||||||
object_link* link = object_to_link(object, object_size);
|
slab_queue_link* link = object_to_link(object, object_size);
|
||||||
|
|
||||||
TRACE_CACHE(this, "returning %p (%p) to %p, %lu used (%lu empty slabs).",
|
TRACE_CACHE(this, "returning %p (%p) to %p, %lu used (%lu empty slabs).",
|
||||||
object, link, source, source->size - source->count,
|
object, link, source, source->size - source->count,
|
||||||
empty_count);
|
empty_count);
|
||||||
|
|
||||||
_push(source->free, link);
|
source->free.Push(link);
|
||||||
source->count++;
|
source->count++;
|
||||||
used_count--;
|
used_count--;
|
||||||
|
|
||||||
@@ -267,8 +265,8 @@ ObjectCache::AssertObjectNotFreed(void* object)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
object_link* link = object_to_link(object, object_size);
|
slab_queue_link* link = object_to_link(object, object_size);
|
||||||
for (object_link* freeLink = source->free; freeLink != NULL;
|
for (slab_queue_link* freeLink = source->free.head; freeLink != NULL;
|
||||||
freeLink = freeLink->next) {
|
freeLink = freeLink->next) {
|
||||||
if (freeLink == link) {
|
if (freeLink == link) {
|
||||||
panic("object_cache: double free of %p (slab %p, cache %p)",
|
panic("object_cache: double free of %p (slab %p, cache %p)",
|
||||||
|
|||||||
@@ -10,10 +10,12 @@
|
|||||||
|
|
||||||
#include <condition_variable.h>
|
#include <condition_variable.h>
|
||||||
#include <lock.h>
|
#include <lock.h>
|
||||||
#include <slab/ObjectDepot.h>
|
|
||||||
#include <slab/Slab.h>
|
#include <slab/Slab.h>
|
||||||
#include <util/DoublyLinkedList.h>
|
#include <util/DoublyLinkedList.h>
|
||||||
|
|
||||||
|
#include "ObjectDepot.h"
|
||||||
|
#include "slab_queue.h"
|
||||||
|
|
||||||
#include "kernel_debug_config.h"
|
#include "kernel_debug_config.h"
|
||||||
#include "slab_debug.h"
|
#include "slab_debug.h"
|
||||||
|
|
||||||
@@ -21,16 +23,12 @@
|
|||||||
struct ResizeRequest;
|
struct ResizeRequest;
|
||||||
|
|
||||||
|
|
||||||
struct object_link {
|
|
||||||
struct object_link* next;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct slab : DoublyLinkedListLinkImpl<slab> {
|
struct slab : DoublyLinkedListLinkImpl<slab> {
|
||||||
void* pages;
|
void* pages;
|
||||||
size_t size; // total number of objects
|
size_t size; // total number of objects
|
||||||
size_t count; // free objects
|
size_t count; // free objects
|
||||||
size_t offset;
|
size_t offset;
|
||||||
object_link* free;
|
slab_queue free;
|
||||||
#if SLAB_OBJECT_CACHE_ALLOCATION_TRACKING
|
#if SLAB_OBJECT_CACHE_ALLOCATION_TRACKING
|
||||||
AllocationTrackingInfo* tracking;
|
AllocationTrackingInfo* tracking;
|
||||||
#endif
|
#endif
|
||||||
@@ -131,17 +129,17 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
static inline void*
|
static inline void*
|
||||||
link_to_object(object_link* link, size_t objectSize)
|
link_to_object(slab_queue_link* link, size_t objectSize)
|
||||||
{
|
{
|
||||||
return ((uint8*)link) - (objectSize - sizeof(object_link));
|
return ((uint8*)link) - (objectSize - sizeof(slab_queue_link));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline object_link*
|
static inline slab_queue_link*
|
||||||
object_to_link(void* object, size_t objectSize)
|
object_to_link(void* object, size_t objectSize)
|
||||||
{
|
{
|
||||||
return (object_link*)(((uint8*)object)
|
return (slab_queue_link*)(((uint8*)object)
|
||||||
+ (objectSize - sizeof(object_link)));
|
+ (objectSize - sizeof(slab_queue_link)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <slab/ObjectDepot.h>
|
#include "ObjectDepot.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
@@ -18,10 +18,10 @@
|
|||||||
|
|
||||||
#include "slab_debug.h"
|
#include "slab_debug.h"
|
||||||
#include "slab_private.h"
|
#include "slab_private.h"
|
||||||
|
#include "slab_queue.h"
|
||||||
|
|
||||||
|
|
||||||
struct DepotMagazine {
|
struct DepotMagazine : public slab_queue_link {
|
||||||
DepotMagazine* next;
|
|
||||||
uint16 current_round;
|
uint16 current_round;
|
||||||
uint16 round_count;
|
uint16 round_count;
|
||||||
void* rounds[0];
|
void* rounds[0];
|
||||||
@@ -138,14 +138,14 @@ exchange_with_full(object_depot* depot, DepotMagazine*& magazine)
|
|||||||
|
|
||||||
SpinLocker _(depot->inner_lock);
|
SpinLocker _(depot->inner_lock);
|
||||||
|
|
||||||
if (depot->full == NULL)
|
if (depot->full.head == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
depot->full_count--;
|
depot->full_count--;
|
||||||
depot->empty_count++;
|
depot->empty_count++;
|
||||||
|
|
||||||
_push(depot->empty, magazine);
|
depot->empty.Push(magazine);
|
||||||
magazine = _pop(depot->full);
|
magazine = (DepotMagazine*)depot->full.Pop();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,21 +158,21 @@ exchange_with_empty(object_depot* depot, DepotMagazine*& magazine,
|
|||||||
|
|
||||||
SpinLocker _(depot->inner_lock);
|
SpinLocker _(depot->inner_lock);
|
||||||
|
|
||||||
if (depot->empty == NULL)
|
if (depot->empty.head == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
depot->empty_count--;
|
depot->empty_count--;
|
||||||
|
|
||||||
if (magazine != NULL) {
|
if (magazine != NULL) {
|
||||||
if (depot->full_count < depot->max_count) {
|
if (depot->full_count < depot->max_count) {
|
||||||
_push(depot->full, magazine);
|
depot->full.Push(magazine);
|
||||||
depot->full_count++;
|
depot->full_count++;
|
||||||
freeMagazine = NULL;
|
freeMagazine = NULL;
|
||||||
} else
|
} else
|
||||||
freeMagazine = magazine;
|
freeMagazine = magazine;
|
||||||
}
|
}
|
||||||
|
|
||||||
magazine = _pop(depot->empty);
|
magazine = (DepotMagazine*)depot->empty.Pop();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ push_empty_magazine(object_depot* depot, DepotMagazine* magazine)
|
|||||||
{
|
{
|
||||||
SpinLocker _(depot->inner_lock);
|
SpinLocker _(depot->inner_lock);
|
||||||
|
|
||||||
_push(depot->empty, magazine);
|
depot->empty.Push(magazine);
|
||||||
depot->empty_count++;
|
depot->empty_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,8 +202,8 @@ object_depot_init(object_depot* depot, size_t capacity, size_t maxCount,
|
|||||||
uint32 flags, void* cookie, void (*return_object)(object_depot* depot,
|
uint32 flags, void* cookie, void (*return_object)(object_depot* depot,
|
||||||
void* cookie, void* object, uint32 flags))
|
void* cookie, void* object, uint32 flags))
|
||||||
{
|
{
|
||||||
depot->full = NULL;
|
depot->full.Init();
|
||||||
depot->empty = NULL;
|
depot->empty.Init();
|
||||||
depot->full_count = depot->empty_count = 0;
|
depot->full_count = depot->empty_count = 0;
|
||||||
depot->max_count = maxCount;
|
depot->max_count = maxCount;
|
||||||
depot->magazine_capacity = capacity;
|
depot->magazine_capacity = capacity;
|
||||||
@@ -336,43 +336,44 @@ object_depot_make_empty(object_depot* depot, uint32 flags)
|
|||||||
|
|
||||||
// collect the store magazines
|
// collect the store magazines
|
||||||
|
|
||||||
DepotMagazine* storeMagazines = NULL;
|
slab_queue storeMagazines;
|
||||||
|
storeMagazines.Init();
|
||||||
|
|
||||||
int cpuCount = smp_get_num_cpus();
|
int cpuCount = smp_get_num_cpus();
|
||||||
for (int i = 0; i < cpuCount; i++) {
|
for (int i = 0; i < cpuCount; i++) {
|
||||||
depot_cpu_store& store = depot->stores[i];
|
depot_cpu_store& store = depot->stores[i];
|
||||||
|
|
||||||
if (store.loaded) {
|
if (store.loaded != NULL) {
|
||||||
_push(storeMagazines, store.loaded);
|
storeMagazines.Push(store.loaded);
|
||||||
store.loaded = NULL;
|
store.loaded = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (store.previous) {
|
if (store.previous != NULL) {
|
||||||
_push(storeMagazines, store.previous);
|
storeMagazines.Push(store.previous);
|
||||||
store.previous = NULL;
|
store.previous = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// detach the depot's full and empty magazines
|
// detach the depot's full and empty magazines
|
||||||
|
|
||||||
DepotMagazine* fullMagazines = depot->full;
|
slab_queue fullMagazines = depot->full;
|
||||||
depot->full = NULL;
|
depot->full.head = depot->full.tail = NULL;
|
||||||
|
|
||||||
DepotMagazine* emptyMagazines = depot->empty;
|
slab_queue emptyMagazines = depot->empty;
|
||||||
depot->empty = NULL;
|
depot->empty.head = depot->empty.tail = NULL;
|
||||||
|
|
||||||
writeLocker.Unlock();
|
writeLocker.Unlock();
|
||||||
|
|
||||||
// free all magazines
|
// free all magazines
|
||||||
|
|
||||||
while (storeMagazines != NULL)
|
while (storeMagazines.head != NULL)
|
||||||
empty_magazine(depot, _pop(storeMagazines), flags);
|
empty_magazine(depot, (DepotMagazine*)storeMagazines.Pop(), flags);
|
||||||
|
|
||||||
while (fullMagazines != NULL)
|
while (fullMagazines.head != NULL)
|
||||||
empty_magazine(depot, _pop(fullMagazines), flags);
|
empty_magazine(depot, (DepotMagazine*)fullMagazines.Pop(), flags);
|
||||||
|
|
||||||
while (emptyMagazines)
|
while (emptyMagazines.head != NULL)
|
||||||
free_magazine(_pop(emptyMagazines), flags);
|
free_magazine((DepotMagazine*)emptyMagazines.Pop(), flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -398,8 +399,8 @@ object_depot_contains_object(object_depot* depot, void* object)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (DepotMagazine* magazine = depot->full; magazine != NULL;
|
for (DepotMagazine* magazine = (DepotMagazine*)depot->full.head; magazine != NULL;
|
||||||
magazine = magazine->next) {
|
magazine = (DepotMagazine*)magazine->next) {
|
||||||
if (magazine->ContainsObject(object))
|
if (magazine->ContainsObject(object))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -416,8 +417,8 @@ object_depot_contains_object(object_depot* depot, void* object)
|
|||||||
void
|
void
|
||||||
dump_object_depot(object_depot* depot)
|
dump_object_depot(object_depot* depot)
|
||||||
{
|
{
|
||||||
kprintf(" full: %p, count %lu\n", depot->full, depot->full_count);
|
kprintf(" full: %p, count %lu\n", depot->full.head, depot->full_count);
|
||||||
kprintf(" empty: %p, count %lu\n", depot->empty, depot->empty_count);
|
kprintf(" empty: %p, count %lu\n", depot->empty.head, depot->empty_count);
|
||||||
kprintf(" max full: %lu\n", depot->max_count);
|
kprintf(" max full: %lu\n", depot->max_count);
|
||||||
kprintf(" capacity: %lu\n", depot->magazine_capacity);
|
kprintf(" capacity: %lu\n", depot->magazine_capacity);
|
||||||
kprintf(" stores:\n");
|
kprintf(" stores:\n");
|
||||||
|
|||||||
@@ -10,14 +10,16 @@
|
|||||||
#include <lock.h>
|
#include <lock.h>
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
|
|
||||||
|
#include "slab_queue.h"
|
||||||
|
|
||||||
|
|
||||||
struct DepotMagazine;
|
struct DepotMagazine;
|
||||||
|
|
||||||
typedef struct object_depot {
|
typedef struct object_depot {
|
||||||
rw_lock outer_lock;
|
rw_lock outer_lock;
|
||||||
spinlock inner_lock;
|
spinlock inner_lock;
|
||||||
DepotMagazine* full;
|
slab_queue full;
|
||||||
DepotMagazine* empty;
|
slab_queue empty;
|
||||||
size_t full_count;
|
size_t full_count;
|
||||||
size_t empty_count;
|
size_t empty_count;
|
||||||
size_t max_count;
|
size_t max_count;
|
||||||
@@ -20,7 +20,6 @@
|
|||||||
#include <elf.h>
|
#include <elf.h>
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
#include <low_resource_manager.h>
|
#include <low_resource_manager.h>
|
||||||
#include <slab/ObjectDepot.h>
|
|
||||||
#include <smp.h>
|
#include <smp.h>
|
||||||
#include <tracing.h>
|
#include <tracing.h>
|
||||||
#include <util/AutoLock.h>
|
#include <util/AutoLock.h>
|
||||||
@@ -28,11 +27,12 @@
|
|||||||
#include <vm/vm.h>
|
#include <vm/vm.h>
|
||||||
#include <vm/VMAddressSpace.h>
|
#include <vm/VMAddressSpace.h>
|
||||||
|
|
||||||
|
#include "SmallObjectCache.h"
|
||||||
#include "HashedObjectCache.h"
|
#include "HashedObjectCache.h"
|
||||||
|
#include "ObjectDepot.h"
|
||||||
#include "MemoryManager.h"
|
#include "MemoryManager.h"
|
||||||
#include "slab_debug.h"
|
#include "slab_debug.h"
|
||||||
#include "slab_private.h"
|
#include "slab_private.h"
|
||||||
#include "SmallObjectCache.h"
|
|
||||||
|
|
||||||
|
|
||||||
#if !USE_GUARDED_HEAP_FOR_OBJECT_CACHE
|
#if !USE_GUARDED_HEAP_FOR_OBJECT_CACHE
|
||||||
@@ -251,7 +251,7 @@ static void
|
|||||||
dump_slab(::slab* slab)
|
dump_slab(::slab* slab)
|
||||||
{
|
{
|
||||||
kprintf(" %p %p %6" B_PRIuSIZE " %6" B_PRIuSIZE " %6" B_PRIuSIZE " %p\n",
|
kprintf(" %p %p %6" B_PRIuSIZE " %6" B_PRIuSIZE " %6" B_PRIuSIZE " %p\n",
|
||||||
slab, slab->pages, slab->size, slab->count, slab->offset, slab->free);
|
slab, slab->pages, slab->size, slab->count, slab->offset, slab->free.head);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1273,7 +1273,7 @@ object_cache_alloc(object_cache* cache, uint32 flags)
|
|||||||
|
|
||||||
ParanoiaChecker _2(source);
|
ParanoiaChecker _2(source);
|
||||||
|
|
||||||
object_link* link = _pop(source->free);
|
slab_queue_link* link = source->free.Pop();
|
||||||
source->count--;
|
source->count--;
|
||||||
cache->used_count++;
|
cache->used_count++;
|
||||||
|
|
||||||
|
|||||||
@@ -24,25 +24,6 @@ void block_allocator_init_boot();
|
|||||||
void block_allocator_init_rest();
|
void block_allocator_init_rest();
|
||||||
|
|
||||||
|
|
||||||
template<typename Type>
|
|
||||||
static inline Type*
|
|
||||||
_pop(Type*& head)
|
|
||||||
{
|
|
||||||
Type* oldHead = head;
|
|
||||||
head = head->next;
|
|
||||||
return oldHead;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<typename Type>
|
|
||||||
static inline void
|
|
||||||
_push(Type*& head, Type* object)
|
|
||||||
{
|
|
||||||
object->next = head;
|
|
||||||
head = object;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline void*
|
static inline void*
|
||||||
slab_internal_alloc(size_t size, uint32 flags)
|
slab_internal_alloc(size_t size, uint32 flags)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2025, Haiku, Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef SLAB_QUEUE_H
|
||||||
|
#define SLAB_QUEUE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
||||||
|
struct slab_queue_link {
|
||||||
|
slab_queue_link* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct slab_queue {
|
||||||
|
slab_queue_link* head;
|
||||||
|
slab_queue_link* tail;
|
||||||
|
|
||||||
|
void Init()
|
||||||
|
{
|
||||||
|
head = tail = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Push(slab_queue_link* item)
|
||||||
|
{
|
||||||
|
item->next = NULL;
|
||||||
|
|
||||||
|
if (tail == NULL) {
|
||||||
|
head = tail = item;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tail->next = item;
|
||||||
|
tail = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
slab_queue_link* Pop()
|
||||||
|
{
|
||||||
|
slab_queue_link* item = head;
|
||||||
|
head = item->next;
|
||||||
|
if (head == NULL)
|
||||||
|
tail = NULL;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SLAB_QUEUE_H
|
||||||
Reference in New Issue
Block a user