kernel: Add mechanism to replace specific object caches with the guarded heap.
This allows the guarded heap to be used in a much more targeted way,
if it's suspected specific object_caches have problems.
Enabled by default for KDEBUG. The new safemode/kernel option is
"guarded_heap_for_object_caches". This accepts a comma-separated
list of quoted strings, optionally with * at beginning and/or end
(but not middle.) Examples:
mbufs* # matches caches starting with "mbufs"
*jumbo9* # matches caches containing "jumbo9"
"*jumbo9 chunks","mbufs*" # matches caches ending with "jumbo9 chunks"
# or starting with "mbufs"
This should help with diagnosing #19973, among others, without needing
to compile custom versions of drivers or anything like that.
Unfortunately it is not possible to use this mechanism to selectively
replace parts of the slab malloc. The slab malloc free() relies on
the MemoryManager to figure out what cache an object belongs to, which
doesn't work if objects of some size classes aren't known to the
MemoryManager at all.
This commit is contained in:
@@ -120,9 +120,6 @@
|
|||||||
// space so it is quite easy to hit limits.
|
// space so it is quite easy to hit limits.
|
||||||
#define DEBUG_HEAPS_DEFAULT slab
|
#define DEBUG_HEAPS_DEFAULT slab
|
||||||
|
|
||||||
// Replace the object cache with the chosen debug heap to force debug features.
|
|
||||||
#define USE_DEBUG_HEAPS_FOR_OBJECT_CACHE 0
|
|
||||||
|
|
||||||
// If 0, disables memory re-use by default in the guarded heap (can be overridden
|
// If 0, disables memory re-use by default in the guarded heap (can be overridden
|
||||||
// via "guarded_heap_options".) This means freed virtual memory is never reused and
|
// via "guarded_heap_options".) This means freed virtual memory is never reused and
|
||||||
// stays invalid, causing any access to crash. This is a magnitude more space
|
// stays invalid, causing any access to crash. This is a magnitude more space
|
||||||
@@ -130,6 +127,13 @@
|
|||||||
// to address space waste.
|
// to address space waste.
|
||||||
#define DEBUG_GUARDED_HEAP_MEMORY_REUSE_DEFAULT 1
|
#define DEBUG_GUARDED_HEAP_MEMORY_REUSE_DEFAULT 1
|
||||||
|
|
||||||
|
// If DEBUG_HEAPS is enabled, allow the guarded heap to replace select object_cache(s)
|
||||||
|
// (but not slab malloc ones) specified via "guarded_heap_for_object_caches".
|
||||||
|
#define GUARDED_HEAP_CAN_REPLACE_OBJECT_CACHES 1
|
||||||
|
|
||||||
|
// Replace all object caches with the chosen debug heap to force debug features.
|
||||||
|
#define USE_DEBUG_HEAPS_FOR_ALL_OBJECT_CACHES 0
|
||||||
|
|
||||||
// Enables additional sanity checks in the slab allocator's memory manager.
|
// Enables additional sanity checks in the slab allocator's memory manager.
|
||||||
#define DEBUG_SLAB_MEMORY_MANAGER_PARANOID_CHECKS 0
|
#define DEBUG_SLAB_MEMORY_MANAGER_PARANOID_CHECKS 0
|
||||||
|
|
||||||
|
|||||||
@@ -504,13 +504,13 @@ guarded_heap_realloc(guarded_heap& heap, void* address, size_t newSize, uint32 f
|
|||||||
if (oldSize == newSize)
|
if (oldSize == newSize)
|
||||||
return address;
|
return address;
|
||||||
|
|
||||||
void* newBlock = malloc_etc(newSize, flags);
|
void* newBlock = guarded_heap_allocate(heap, newSize, 0, flags);
|
||||||
if (newBlock == NULL)
|
if (newBlock == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
memcpy(newBlock, address, min_c(oldSize, newSize));
|
memcpy(newBlock, address, min_c(oldSize, newSize));
|
||||||
|
|
||||||
free_etc(address, flags);
|
guarded_heap_free(heap, address, flags);
|
||||||
return newBlock;
|
return newBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -874,7 +874,7 @@ guarded_heap_realloc_etc(void* address, size_t newSize, uint32 flags)
|
|||||||
|
|
||||||
kernel_heap_implementation kernel_guarded_heap = {
|
kernel_heap_implementation kernel_guarded_heap = {
|
||||||
"guarded_heap",
|
"guarded_heap",
|
||||||
#if USE_DEBUG_HEAPS_FOR_OBJECT_CACHE
|
#if USE_DEBUG_HEAPS_FOR_ALL_OBJECT_CACHES
|
||||||
// This requires a lot of up-front memory to boot at all...
|
// This requires a lot of up-front memory to boot at all...
|
||||||
/* initial_size */ 128 * 1024 * 1024,
|
/* initial_size */ 128 * 1024 * 1024,
|
||||||
// ... and a lot of reserves to keep running.
|
// ... and a lot of reserves to keep running.
|
||||||
|
|||||||
@@ -8,8 +8,9 @@
|
|||||||
#if DEBUG_HEAPS
|
#if DEBUG_HEAPS
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <heap.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <heap.h>
|
||||||
#include <vm/vm.h>
|
#include <vm/vm.h>
|
||||||
#include <vm/vm_page.h>
|
#include <vm/vm_page.h>
|
||||||
#include <slab/Slab.h>
|
#include <slab/Slab.h>
|
||||||
@@ -28,33 +29,27 @@
|
|||||||
|
|
||||||
#define HEAP_SYMBOL_NAME(NAME) kernel_##NAME##_heap
|
#define HEAP_SYMBOL_NAME(NAME) kernel_##NAME##_heap
|
||||||
#define HEAP_SYMBOL(NAME) HEAP_SYMBOL_NAME(NAME)
|
#define HEAP_SYMBOL(NAME) HEAP_SYMBOL_NAME(NAME)
|
||||||
static kernel_heap_implementation* sHeap = &HEAP_SYMBOL(DEBUG_HEAPS_DEFAULT);
|
static kernel_heap_implementation* sActiveHeaps[2] = { &HEAP_SYMBOL(DEBUG_HEAPS_DEFAULT) };
|
||||||
|
|
||||||
|
#if GUARDED_HEAP_CAN_REPLACE_OBJECT_CACHES
|
||||||
|
struct CacheSelector {
|
||||||
|
char name[32];
|
||||||
|
bool globPrefix : 1;
|
||||||
|
bool globSuffix : 1;
|
||||||
|
};
|
||||||
|
static CacheSelector* sGuardedHeapForObjectCaches = NULL;
|
||||||
|
static int32 sGuardedHeapForObjectCachesCount = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
status_t
|
static status_t
|
||||||
heap_init(struct kernel_args* args)
|
init_heap(struct kernel_args* args, kernel_heap_implementation* heap)
|
||||||
{
|
{
|
||||||
char buffer[32];
|
|
||||||
size_t bufferSize = sizeof(buffer);
|
|
||||||
if (get_safemode_option_early(args, "kernel_malloc", buffer, &bufferSize) == B_OK) {
|
|
||||||
if (strcmp(buffer, "guarded") == 0)
|
|
||||||
sHeap = &kernel_guarded_heap;
|
|
||||||
else if (strcmp(buffer, "debug") == 0)
|
|
||||||
sHeap = &kernel_debug_heap;
|
|
||||||
#if !USE_DEBUG_HEAPS_FOR_OBJECT_CACHE
|
|
||||||
else if (strcmp(buffer, "slab") == 0)
|
|
||||||
sHeap = &kernel_slab_heap;
|
|
||||||
#endif
|
|
||||||
else
|
|
||||||
panic("unknown or unavailable kernel heap '%s'!", buffer);
|
|
||||||
}
|
|
||||||
dprintf("kernel malloc: using %s\n", sHeap->name);
|
|
||||||
|
|
||||||
addr_t heapBase = 0;
|
addr_t heapBase = 0;
|
||||||
size_t heapSize = sHeap->initial_size;
|
size_t heapSize = heap->initial_size;
|
||||||
if (heapSize != 0) {
|
if (heapSize != 0) {
|
||||||
// try to accomodate low memory systems
|
// try to accomodate low memory systems
|
||||||
while (heapSize > (vm_page_num_pages() * B_PAGE_SIZE) / 8)
|
while (heapSize > (vm_page_num_pages() * B_PAGE_SIZE) / 8)
|
||||||
@@ -68,83 +63,247 @@ heap_init(struct kernel_args* args)
|
|||||||
TRACE(("heap at 0x%lx\n", heapBase));
|
TRACE(("heap at 0x%lx\n", heapBase));
|
||||||
}
|
}
|
||||||
|
|
||||||
return sHeap->init(args, heapBase, heapSize);
|
return heap->init(args, heapBase, heapSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if GUARDED_HEAP_CAN_REPLACE_OBJECT_CACHES
|
||||||
|
bool
|
||||||
|
guarded_heap_replaces_object_cache(const char* name)
|
||||||
|
{
|
||||||
|
if (sGuardedHeapForObjectCaches == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool match = false;
|
||||||
|
for (int32 i = 0; !match && i < sGuardedHeapForObjectCachesCount; i++) {
|
||||||
|
CacheSelector& selector = sGuardedHeapForObjectCaches[i];
|
||||||
|
if (selector.globPrefix && selector.globSuffix) {
|
||||||
|
if (strstr(name, selector.name) != NULL)
|
||||||
|
match = true;
|
||||||
|
} else if (selector.globPrefix) {
|
||||||
|
int32 nameLen = strlen(name), selectorLen = strlen(selector.name);
|
||||||
|
if (strcmp(name + (nameLen - selectorLen), selector.name) == 0)
|
||||||
|
match = true;
|
||||||
|
} else if (selector.globSuffix) {
|
||||||
|
if (strncmp(name, selector.name, strlen(selector.name)) == 0)
|
||||||
|
match = true;
|
||||||
|
} else {
|
||||||
|
if (strcmp(name, selector.name) == 0)
|
||||||
|
match = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match)
|
||||||
|
dprintf("using guarded heap for object_cache \"%s\"\n", name);
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
init_object_cache_replacements(struct kernel_args* args)
|
||||||
|
{
|
||||||
|
char buffer[1024];
|
||||||
|
size_t bufferSize = sizeof(buffer);
|
||||||
|
if (get_safemode_option_early(args, "guarded_heap_for_object_caches",
|
||||||
|
buffer, &bufferSize) != B_OK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (sActiveHeaps[0] != &kernel_guarded_heap) {
|
||||||
|
// We need to initialize the guarded heap, too.
|
||||||
|
sActiveHeaps[1] = &kernel_guarded_heap;
|
||||||
|
init_heap(args, sActiveHeaps[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
sGuardedHeapForObjectCaches = (CacheSelector*)
|
||||||
|
kernel_guarded_heap.memalign(0, B_PAGE_SIZE, 0);
|
||||||
|
memset(sGuardedHeapForObjectCaches, 0, B_PAGE_SIZE);
|
||||||
|
|
||||||
|
// Parse the option.
|
||||||
|
const char* option = buffer;
|
||||||
|
while (*option != '\0') {
|
||||||
|
CacheSelector& selector
|
||||||
|
= sGuardedHeapForObjectCaches[sGuardedHeapForObjectCachesCount++];
|
||||||
|
|
||||||
|
size_t nameLength = 0;
|
||||||
|
char quoteEnd = '\0';
|
||||||
|
bool phraseEnd = false;
|
||||||
|
bool seenGlob = false;
|
||||||
|
while (!phraseEnd && nameLength < (sizeof(selector.name) - 1)) {
|
||||||
|
if (quoteEnd == '\0' && isspace(*option)) {
|
||||||
|
option++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (*option) {
|
||||||
|
case '"':
|
||||||
|
case '\'':
|
||||||
|
if (quoteEnd == '\0')
|
||||||
|
quoteEnd = *option;
|
||||||
|
else if (quoteEnd == *option)
|
||||||
|
quoteEnd = '\0';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\0':
|
||||||
|
case ',':
|
||||||
|
phraseEnd = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '*':
|
||||||
|
if (nameLength == 0)
|
||||||
|
selector.globPrefix = true;
|
||||||
|
else
|
||||||
|
seenGlob = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\\':
|
||||||
|
option++;
|
||||||
|
// fall through
|
||||||
|
default:
|
||||||
|
if (seenGlob) {
|
||||||
|
dprintf("heap_init: error: unsupported glob pattern\n");
|
||||||
|
seenGlob = false;
|
||||||
|
}
|
||||||
|
selector.name[nameLength++] = *option;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
option++;
|
||||||
|
}
|
||||||
|
if (seenGlob)
|
||||||
|
selector.globSuffix = true;
|
||||||
|
if (!phraseEnd) {
|
||||||
|
dprintf("heap_init: error: pattern overflow after '%s'\n", selector.name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf("guarded_heap_for_object_caches: loaded %" B_PRId32 " selectors\n",
|
||||||
|
sGuardedHeapForObjectCachesCount);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
heap_init(struct kernel_args* args)
|
||||||
|
{
|
||||||
|
char buffer[32];
|
||||||
|
size_t bufferSize = sizeof(buffer);
|
||||||
|
if (get_safemode_option_early(args, "kernel_malloc", buffer, &bufferSize) == B_OK) {
|
||||||
|
if (strcmp(buffer, "guarded") == 0)
|
||||||
|
sActiveHeaps[0] = &kernel_guarded_heap;
|
||||||
|
else if (strcmp(buffer, "debug") == 0)
|
||||||
|
sActiveHeaps[0] = &kernel_debug_heap;
|
||||||
|
#if !USE_DEBUG_HEAPS_FOR_ALL_OBJECT_CACHES
|
||||||
|
else if (strcmp(buffer, "slab") == 0)
|
||||||
|
sActiveHeaps[0] = &kernel_slab_heap;
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
panic("unknown or unavailable kernel heap '%s'!", buffer);
|
||||||
|
}
|
||||||
|
dprintf("kernel malloc: using %s\n", sActiveHeaps[0]->name);
|
||||||
|
|
||||||
|
status_t status = init_heap(args, sActiveHeaps[0]);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
#if GUARDED_HEAP_CAN_REPLACE_OBJECT_CACHES
|
||||||
|
init_object_cache_replacements(args);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
heap_init_post_area()
|
heap_init_post_area()
|
||||||
{
|
{
|
||||||
if (sHeap->init_post_area == NULL)
|
for (size_t i = 0; i < B_COUNT_OF(sActiveHeaps); i++) {
|
||||||
return B_OK;
|
if (sActiveHeaps[i] == NULL || sActiveHeaps[i]->init_post_area == NULL)
|
||||||
return sHeap->init_post_area();
|
continue;
|
||||||
|
|
||||||
|
status_t status = sActiveHeaps[i]->init_post_area();
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
heap_init_post_sem()
|
heap_init_post_sem()
|
||||||
{
|
{
|
||||||
if (sHeap->init_post_sem == NULL)
|
for (size_t i = 0; i < B_COUNT_OF(sActiveHeaps); i++) {
|
||||||
return B_OK;
|
if (sActiveHeaps[i] == NULL || sActiveHeaps[i]->init_post_sem == NULL)
|
||||||
return sHeap->init_post_sem();
|
continue;
|
||||||
|
|
||||||
|
status_t status = sActiveHeaps[i]->init_post_sem();
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
heap_init_post_thread()
|
heap_init_post_thread()
|
||||||
{
|
{
|
||||||
if (sHeap->init_post_thread == NULL)
|
for (size_t i = 0; i < B_COUNT_OF(sActiveHeaps); i++) {
|
||||||
return B_OK;
|
if (sActiveHeaps[i] == NULL || sActiveHeaps[i]->init_post_thread == NULL)
|
||||||
return sHeap->init_post_thread();
|
continue;
|
||||||
|
|
||||||
|
status_t status = sActiveHeaps[i]->init_post_thread();
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void*
|
void*
|
||||||
memalign(size_t alignment, size_t size)
|
memalign(size_t alignment, size_t size)
|
||||||
{
|
{
|
||||||
return sHeap->memalign(alignment, size, 0);
|
return sActiveHeaps[0]->memalign(alignment, size, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void*
|
void*
|
||||||
memalign_etc(size_t alignment, size_t size, uint32 flags)
|
memalign_etc(size_t alignment, size_t size, uint32 flags)
|
||||||
{
|
{
|
||||||
return sHeap->memalign(alignment, size, flags);
|
return sActiveHeaps[0]->memalign(alignment, size, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
free_etc(void* address, uint32 flags)
|
free_etc(void* address, uint32 flags)
|
||||||
{
|
{
|
||||||
return sHeap->free(address, flags);
|
return sActiveHeaps[0]->free(address, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
free(void *address)
|
free(void *address)
|
||||||
{
|
{
|
||||||
return sHeap->free(address, 0);
|
return sActiveHeaps[0]->free(address, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void*
|
void*
|
||||||
malloc(size_t size)
|
malloc(size_t size)
|
||||||
{
|
{
|
||||||
return sHeap->memalign(0, size, 0);
|
return sActiveHeaps[0]->memalign(0, size, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void*
|
void*
|
||||||
realloc_etc(void* address, size_t newSize, uint32 flags)
|
realloc_etc(void* address, size_t newSize, uint32 flags)
|
||||||
{
|
{
|
||||||
return sHeap->realloc(address, newSize, flags);
|
return sActiveHeaps[0]->realloc(address, newSize, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void*
|
void*
|
||||||
realloc(void *address, size_t newSize)
|
realloc(void *address, size_t newSize)
|
||||||
{
|
{
|
||||||
return sHeap->realloc(address, newSize, 0);
|
return sActiveHeaps[0]->realloc(address, newSize, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -154,12 +313,12 @@ posix_memalign(void** _pointer, size_t alignment, size_t size)
|
|||||||
if ((alignment & (sizeof(void*) - 1)) != 0 || _pointer == NULL)
|
if ((alignment & (sizeof(void*) - 1)) != 0 || _pointer == NULL)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
*_pointer = sHeap->memalign(alignment, size, 0);
|
*_pointer = sActiveHeaps[0]->memalign(alignment, size, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if USE_DEBUG_HEAPS_FOR_OBJECT_CACHE
|
#if USE_DEBUG_HEAPS_FOR_ALL_OBJECT_CACHES
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - Slab API
|
// #pragma mark - Slab API
|
||||||
@@ -218,7 +377,7 @@ object_cache_set_minimum_reserve(object_cache* cache, size_t objectCount)
|
|||||||
void*
|
void*
|
||||||
object_cache_alloc(object_cache* cache, uint32 flags)
|
object_cache_alloc(object_cache* cache, uint32 flags)
|
||||||
{
|
{
|
||||||
void* object = sHeap->memalign(cache->alignment, cache->object_size, flags);
|
void* object = sActiveHeaps[0]->memalign(cache->alignment, cache->object_size, flags);
|
||||||
if (object == NULL)
|
if (object == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -233,7 +392,7 @@ object_cache_free(object_cache* cache, void* object, uint32 flags)
|
|||||||
{
|
{
|
||||||
if (cache->destructor != NULL)
|
if (cache->destructor != NULL)
|
||||||
cache->destructor(cache->cookie, object);
|
cache->destructor(cache->cookie, object);
|
||||||
return sHeap->free(object, flags);
|
return sActiveHeaps[0]->free(object, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -281,7 +440,7 @@ slab_init_post_thread()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // USE_DEBUG_HEAPS_FOR_OBJECT_CACHE
|
#endif // USE_DEBUG_HEAPS_FOR_ALL_OBJECT_CACHES
|
||||||
|
|
||||||
|
|
||||||
#endif // DEBUG_HEAPS
|
#endif // DEBUG_HEAPS
|
||||||
|
|||||||
@@ -28,5 +28,7 @@ extern kernel_heap_implementation kernel_slab_heap;
|
|||||||
extern kernel_heap_implementation kernel_guarded_heap;
|
extern kernel_heap_implementation kernel_guarded_heap;
|
||||||
extern kernel_heap_implementation kernel_debug_heap;
|
extern kernel_heap_implementation kernel_debug_heap;
|
||||||
|
|
||||||
|
bool guarded_heap_replaces_object_cache(const char* name);
|
||||||
|
|
||||||
|
|
||||||
#endif // _KERNEL_DEBUG_HEAPS_H
|
#endif // _KERNEL_DEBUG_HEAPS_H
|
||||||
|
|||||||
@@ -34,8 +34,12 @@
|
|||||||
#include "slab_debug.h"
|
#include "slab_debug.h"
|
||||||
#include "slab_private.h"
|
#include "slab_private.h"
|
||||||
|
|
||||||
|
#if DEBUG_HEAPS
|
||||||
|
#include "../debug/heaps.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !USE_DEBUG_HEAPS_FOR_OBJECT_CACHE
|
|
||||||
|
#if !USE_DEBUG_HEAPS_FOR_ALL_OBJECT_CACHES
|
||||||
|
|
||||||
|
|
||||||
typedef DoublyLinkedList<ObjectCache> ObjectCacheList;
|
typedef DoublyLinkedList<ObjectCache> ObjectCacheList;
|
||||||
@@ -1164,6 +1168,23 @@ create_object_cache_etc(const char* name, size_t objectSize, size_t alignment,
|
|||||||
uint32 flags, void* cookie, object_cache_constructor constructor,
|
uint32 flags, void* cookie, object_cache_constructor constructor,
|
||||||
object_cache_destructor destructor, object_cache_reclaimer reclaimer)
|
object_cache_destructor destructor, object_cache_reclaimer reclaimer)
|
||||||
{
|
{
|
||||||
|
#if DEBUG_HEAPS && GUARDED_HEAP_CAN_REPLACE_OBJECT_CACHES
|
||||||
|
if (guarded_heap_replaces_object_cache(name)) {
|
||||||
|
ObjectCache* cache = (ObjectCache*)
|
||||||
|
kernel_guarded_heap.memalign(0, sizeof(ObjectCache), flags);
|
||||||
|
memset((void*)cache, 0, sizeof(ObjectCache));
|
||||||
|
strcpy(cache->name, name);
|
||||||
|
cache->object_size = objectSize;
|
||||||
|
cache->alignment = alignment;
|
||||||
|
cache->constructor = constructor;
|
||||||
|
cache->destructor = destructor;
|
||||||
|
cache->cookie = cookie;
|
||||||
|
|
||||||
|
cache->flags = (uint32)-1;
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ObjectCache* cache;
|
ObjectCache* cache;
|
||||||
|
|
||||||
if (objectSize == 0) {
|
if (objectSize == 0) {
|
||||||
@@ -1191,6 +1212,13 @@ create_object_cache_etc(const char* name, size_t objectSize, size_t alignment,
|
|||||||
void
|
void
|
||||||
delete_object_cache(object_cache* cache)
|
delete_object_cache(object_cache* cache)
|
||||||
{
|
{
|
||||||
|
#if DEBUG_HEAPS && GUARDED_HEAP_CAN_REPLACE_OBJECT_CACHES
|
||||||
|
if (cache->flags == (uint32)-1) {
|
||||||
|
kernel_guarded_heap.free(cache, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
T(Delete(cache));
|
T(Delete(cache));
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -1224,6 +1252,11 @@ delete_object_cache(object_cache* cache)
|
|||||||
status_t
|
status_t
|
||||||
object_cache_set_minimum_reserve(object_cache* cache, size_t objectCount)
|
object_cache_set_minimum_reserve(object_cache* cache, size_t objectCount)
|
||||||
{
|
{
|
||||||
|
#if DEBUG_HEAPS && GUARDED_HEAP_CAN_REPLACE_OBJECT_CACHES
|
||||||
|
if (cache->flags == (uint32)-1)
|
||||||
|
return B_OK;
|
||||||
|
#endif
|
||||||
|
|
||||||
MutexLocker _(cache->lock);
|
MutexLocker _(cache->lock);
|
||||||
|
|
||||||
if (cache->min_object_reserve == objectCount)
|
if (cache->min_object_reserve == objectCount)
|
||||||
@@ -1240,6 +1273,16 @@ object_cache_set_minimum_reserve(object_cache* cache, size_t objectCount)
|
|||||||
void*
|
void*
|
||||||
object_cache_alloc(object_cache* cache, uint32 flags)
|
object_cache_alloc(object_cache* cache, uint32 flags)
|
||||||
{
|
{
|
||||||
|
#if DEBUG_HEAPS && GUARDED_HEAP_CAN_REPLACE_OBJECT_CACHES
|
||||||
|
if (cache->flags == (uint32)-1) {
|
||||||
|
void* object = kernel_guarded_heap.memalign(cache->alignment,
|
||||||
|
cache->object_size, flags);
|
||||||
|
if (cache->constructor != NULL)
|
||||||
|
cache->constructor(cache->cookie, object);
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void* object = NULL;
|
void* object = NULL;
|
||||||
if ((cache->flags & CACHE_NO_DEPOT) == 0)
|
if ((cache->flags & CACHE_NO_DEPOT) == 0)
|
||||||
object = object_depot_obtain(&cache->depot);
|
object = object_depot_obtain(&cache->depot);
|
||||||
@@ -1307,6 +1350,15 @@ object_cache_alloc(object_cache* cache, uint32 flags)
|
|||||||
void
|
void
|
||||||
object_cache_free(object_cache* cache, void* object, uint32 flags)
|
object_cache_free(object_cache* cache, void* object, uint32 flags)
|
||||||
{
|
{
|
||||||
|
#if DEBUG_HEAPS && GUARDED_HEAP_CAN_REPLACE_OBJECT_CACHES
|
||||||
|
if (cache->flags == (uint32)-1) {
|
||||||
|
if (cache->destructor != NULL)
|
||||||
|
cache->destructor(cache->cookie, object);
|
||||||
|
kernel_guarded_heap.free(object, flags);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (object == NULL)
|
if (object == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -1348,6 +1400,11 @@ object_cache_free(object_cache* cache, void* object, uint32 flags)
|
|||||||
status_t
|
status_t
|
||||||
object_cache_reserve(object_cache* cache, size_t objectCount, uint32 flags)
|
object_cache_reserve(object_cache* cache, size_t objectCount, uint32 flags)
|
||||||
{
|
{
|
||||||
|
#if DEBUG_HEAPS && GUARDED_HEAP_CAN_REPLACE_OBJECT_CACHES
|
||||||
|
if (cache->flags == (uint32)-1)
|
||||||
|
return B_OK;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (objectCount == 0)
|
if (objectCount == 0)
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
@@ -1453,4 +1510,4 @@ slab_init_post_thread()
|
|||||||
RANGE_MARKER_FUNCTION_END(Slab)
|
RANGE_MARKER_FUNCTION_END(Slab)
|
||||||
|
|
||||||
|
|
||||||
#endif // !USE_DEBUG_HEAPS_FOR_OBJECT_CACHE
|
#endif // !USE_DEBUG_HEAPS_FOR_ALL_OBJECT_CACHES
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
#include "MemoryManager.h"
|
#include "MemoryManager.h"
|
||||||
|
|
||||||
|
|
||||||
#if !USE_DEBUG_HEAPS_FOR_OBJECT_CACHE
|
#if !USE_DEBUG_HEAPS_FOR_ALL_OBJECT_CACHES
|
||||||
|
|
||||||
|
|
||||||
#if DEBUG_HEAPS
|
#if DEBUG_HEAPS
|
||||||
@@ -353,7 +353,7 @@ heap_init_post_thread()
|
|||||||
RANGE_MARKER_FUNCTION_END(slab_allocator)
|
RANGE_MARKER_FUNCTION_END(slab_allocator)
|
||||||
|
|
||||||
|
|
||||||
#else // USE_DEBUG_HEAPS_FOR_OBJECT_CACHE
|
#else // USE_DEBUG_HEAPS_FOR_ALL_OBJECT_CACHES
|
||||||
|
|
||||||
|
|
||||||
void*
|
void*
|
||||||
@@ -364,4 +364,4 @@ block_alloc_early(size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // USE_DEBUG_HEAPS_FOR_OBJECT_CACHE
|
#endif // USE_DEBUG_HEAPS_FOR_ALL_OBJECT_CACHES
|
||||||
|
|||||||
Reference in New Issue
Block a user