From c1de3c34b3370a5a00d8e74b4646343814016431 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 9 Mar 2008 17:44:55 +0000 Subject: [PATCH] Added deferred_free() function, that can be used to free allocations in code that has interrupts disabled. The chunks of memories are queued and free()d periodically by a kernel daemon. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24332 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/heap.h | 2 ++ src/system/kernel/heap.cpp | 46 +++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/headers/private/kernel/heap.h b/headers/private/kernel/heap.h index 6be504a561..0f60cf4d14 100644 --- a/headers/private/kernel/heap.h +++ b/headers/private/kernel/heap.h @@ -24,6 +24,8 @@ extern "C" { void *memalign(size_t alignment, size_t size); +void deferred_free(void* block); + status_t heap_init(addr_t heapBase, size_t heapSize); status_t heap_init_post_sem(); status_t heap_init_post_thread(); diff --git a/src/system/kernel/heap.cpp b/src/system/kernel/heap.cpp index 831c310f5a..8bd03af776 100644 --- a/src/system/kernel/heap.cpp +++ b/src/system/kernel/heap.cpp @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include //#define TRACE_HEAP @@ -81,6 +83,10 @@ typedef struct heap_allocator_s { heap_allocator_s * next; } heap_allocator; +struct DeferredFreeListEntry : DoublyLinkedListLinkImpl { +}; +typedef DoublyLinkedList DeferredFreeList; + static heap_allocator *sHeapList = NULL; static heap_allocator *sLastGrowRequest = NULL; static heap_allocator *sGrowHeap = NULL; @@ -88,6 +94,10 @@ static thread_id sHeapGrowThread = -1; static sem_id sHeapGrowSem = -1; static sem_id sHeapGrownNotify = -1; +static DeferredFreeList sDeferredFreeList; +static spinlock sDeferredFreeListLock; + + // #pragma mark - Tracing @@ -962,6 +972,25 @@ heap_realloc(heap_allocator *heap, void *address, void **newAddress, } +static void +deferred_deleter(void *arg, int iteration) +{ + // move entries to on-stack list + InterruptsSpinLocker locker(sDeferredFreeListLock); + if (sDeferredFreeList.IsEmpty()) + return; + + DeferredFreeList entries; + entries.MoveFrom(&sDeferredFreeList); + + locker.Unlock(); + + // free the entries + while (DeferredFreeListEntry* entry = entries.RemoveHead()) + free(entry); +} + + // #pragma mark - @@ -1092,6 +1121,9 @@ heap_init_post_thread() return sHeapGrowThread; } + if (register_kernel_daemon(deferred_deleter, NULL, 50) != B_OK) + panic("heap_init_post_thread(): failed to init deferred deleter"); + send_signal_etc(sHeapGrowThread, SIGCONT, B_DO_NOT_RESCHEDULE); return B_OK; } @@ -1236,3 +1268,17 @@ calloc(size_t numElements, size_t size) return address; } + + +void +deferred_free(void* block) +{ + if (block == NULL) + return; + + // TODO: Use SinglyLinkedList, so that we only need sizeof(void*). + DeferredFreeListEntry* entry = new(block) DeferredFreeListEntry; + + InterruptsSpinLocker _(sDeferredFreeListLock); + sDeferredFreeList.Add(entry); +}