From 8d1316fd23616f6dac131a0eba5dab08acc6e76d Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 22 Jan 2010 21:19:23 +0000 Subject: [PATCH] Replaced CACHE_DONT_SLEEP by two new flags CACHE_DONT_WAIT_FOR_MEMORY and CACHE_DONT_LOCK_KERNEL_SPACE. If the former is given, the slab memory manager does not wait when reserving memory or pages. The latter prevents area operations. The new flags add a bit of flexibility. E.g. when allocating page mapping objects for userland areas CACHE_DONT_WAIT_FOR_MEMORY is sufficient, i.e. the allocation will succeed as long as pages are available. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35246 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/slab/Slab.h | 15 +++++----- src/libs/compat/freebsd_network/mbuf.c | 2 +- .../arch/ppc/arch_vm_translation_map.cpp | 8 +++-- .../arch/x86/arch_vm_translation_map.cpp | 18 ++++++++--- src/system/kernel/slab/MemoryManager.cpp | 30 +++++++++---------- src/system/kernel/slab/ObjectDepot.cpp | 7 ++--- src/system/kernel/slab/Slab.cpp | 7 +++-- src/system/kernel/slab/allocator.cpp | 5 +++- src/system/kernel/vm/VMAnonymousCache.cpp | 9 +++--- src/system/kernel/vm/vm.cpp | 5 +++- 10 files changed, 64 insertions(+), 42 deletions(-) diff --git a/headers/private/kernel/slab/Slab.h b/headers/private/kernel/slab/Slab.h index 3723cf6cee..f8f3f1c9ac 100644 --- a/headers/private/kernel/slab/Slab.h +++ b/headers/private/kernel/slab/Slab.h @@ -14,16 +14,17 @@ enum { /* create_object_cache_etc flags */ - CACHE_NO_DEPOT = 1 << 0, - CACHE_UNLOCKED_PAGES = 1 << 1, - CACHE_LARGE_SLAB = 1 << 2, + CACHE_NO_DEPOT = 1 << 0, + CACHE_UNLOCKED_PAGES = 1 << 1, + CACHE_LARGE_SLAB = 1 << 2, - /* object_cache_alloc flags */ - CACHE_DONT_SLEEP = 1 << 8, + /* object_cache_{alloc,free}() flags */ + CACHE_DONT_WAIT_FOR_MEMORY = 1 << 8, + CACHE_DONT_LOCK_KERNEL_SPACE = 1 << 9, /* internal */ - CACHE_ALIGN_ON_SIZE = 1 << 30, - CACHE_DURING_BOOT = 1 << 31 + CACHE_ALIGN_ON_SIZE = 1 << 30, + CACHE_DURING_BOOT = 1 << 31 }; struct ObjectCache; diff --git a/src/libs/compat/freebsd_network/mbuf.c b/src/libs/compat/freebsd_network/mbuf.c index 2fb6f46dae..ce96d5d38e 100644 --- a/src/libs/compat/freebsd_network/mbuf.c +++ b/src/libs/compat/freebsd_network/mbuf.c @@ -36,7 +36,7 @@ static int m_to_oc_flags(int how) { if (how & M_NOWAIT) - return CACHE_DONT_SLEEP; + return CACHE_DONT_WAIT_FOR_MEMORY; return 0; } diff --git a/src/system/kernel/arch/ppc/arch_vm_translation_map.cpp b/src/system/kernel/arch/ppc/arch_vm_translation_map.cpp index 1cab9f9fc7..a0c79aacc4 100644 --- a/src/system/kernel/arch/ppc/arch_vm_translation_map.cpp +++ b/src/system/kernel/arch/ppc/arch_vm_translation_map.cpp @@ -518,8 +518,12 @@ PPCVMTranslationMap::UnmapPage(VMArea* area, addr_t address) locker.Unlock(); - if (mapping != NULL) - object_cache_free(gPageMappingsObjectCache, mapping, CACHE_DONT_SLEEP); + if (mapping != NULL) { + bool isKernelSpace = area->address_space == VMAddressSpace::Kernel(); + object_cache_free(gPageMappingsObjectCache, mapping, + CACHE_DONT_WAIT_FOR_MEMORY + | (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0)); + } return B_OK; } diff --git a/src/system/kernel/arch/x86/arch_vm_translation_map.cpp b/src/system/kernel/arch/x86/arch_vm_translation_map.cpp index b4b68abc7f..eb62e57bb2 100644 --- a/src/system/kernel/arch/x86/arch_vm_translation_map.cpp +++ b/src/system/kernel/arch/x86/arch_vm_translation_map.cpp @@ -628,8 +628,12 @@ X86VMTranslationMap::UnmapPage(VMArea* area, addr_t address) locker.Unlock(); - if (mapping != NULL) - object_cache_free(gPageMappingsObjectCache, mapping, CACHE_DONT_SLEEP); + if (mapping != NULL) { + bool isKernelSpace = area->address_space == VMAddressSpace::Kernel(); + object_cache_free(gPageMappingsObjectCache, mapping, + CACHE_DONT_WAIT_FOR_MEMORY + | (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0)); + } return B_OK; } @@ -738,8 +742,11 @@ X86VMTranslationMap::UnmapPages(VMArea* area, addr_t base, size_t size) locker.Unlock(); // free removed mappings + bool isKernelSpace = area->address_space == VMAddressSpace::Kernel(); + uint32 freeFlags = CACHE_DONT_WAIT_FOR_MEMORY + | (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0); while (vm_page_mapping* mapping = queue.RemoveHead()) - object_cache_free(gPageMappingsObjectCache, mapping, CACHE_DONT_SLEEP); + object_cache_free(gPageMappingsObjectCache, mapping, freeFlags); } @@ -823,8 +830,11 @@ X86VMTranslationMap::UnmapArea(VMArea* area, bool deletingAddressSpace, locker.Unlock(); + bool isKernelSpace = area->address_space == VMAddressSpace::Kernel(); + uint32 freeFlags = CACHE_DONT_WAIT_FOR_MEMORY + | (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0); while (vm_page_mapping* mapping = mappings.RemoveHead()) - object_cache_free(gPageMappingsObjectCache, mapping, CACHE_DONT_SLEEP); + object_cache_free(gPageMappingsObjectCache, mapping, freeFlags); } diff --git a/src/system/kernel/slab/MemoryManager.cpp b/src/system/kernel/slab/MemoryManager.cpp index 3fc28d34aa..4d6328f865 100644 --- a/src/system/kernel/slab/MemoryManager.cpp +++ b/src/system/kernel/slab/MemoryManager.cpp @@ -140,7 +140,6 @@ MemoryManager::Allocate(ObjectCache* cache, uint32 flags, void*& _pages) } else chunk = _pop(area->unmappedFreeChunks); - if (++area->usedChunkCount == area->chunkCount) { areaPool->partialAreas.Remove(area); areaPool->fullAreas.Add(area); @@ -160,7 +159,6 @@ MemoryManager::Allocate(ObjectCache* cache, uint32 flags, void*& _pages) } } - chunk->cache = cache; _pages = (void*)chunkAddress; @@ -246,6 +244,13 @@ MemoryManager::_AreaPoolFor(size_t chunkSize) /*static*/ status_t MemoryManager::_GetPartialArea(AreaPool* areaPool, uint32 flags, Area*& _area) { + if ((flags & CACHE_DONT_LOCK_KERNEL_SPACE) != 0) { + // We can't create an area with this limitation and we must not wait for + // someone else doing that. + _area = areaPool->partialAreas.Head(); + return _area != NULL ? B_OK : B_WOULD_BLOCK; + } + while (true) { Area* area = areaPool->partialAreas.Head(); if (area != NULL) { @@ -259,7 +264,7 @@ MemoryManager::_GetPartialArea(AreaPool* areaPool, uint32 flags, Area*& _area) if (sAllocationEntryDontWait != NULL) { allocationEntry = sAllocationEntryDontWait; } else if (sAllocationEntryCanWait != NULL - && (flags & CACHE_DONT_SLEEP) == 0) { + && (flags & CACHE_DONT_WAIT_FOR_MEMORY) == 0) { allocationEntry = sAllocationEntryCanWait; } else break; @@ -273,8 +278,9 @@ MemoryManager::_GetPartialArea(AreaPool* areaPool, uint32 flags, Area*& _area) } // prepare the allocation entry others can wait on - AllocationEntry*& allocationEntry = (flags & CACHE_DONT_SLEEP) != 0 - ? sAllocationEntryDontWait : sAllocationEntryCanWait; + AllocationEntry*& allocationEntry + = (flags & CACHE_DONT_WAIT_FOR_MEMORY) != 0 + ? sAllocationEntryDontWait : sAllocationEntryCanWait; AllocationEntry myResizeEntry; allocationEntry = &myResizeEntry; @@ -308,10 +314,7 @@ MemoryManager::_AllocateArea(size_t chunkSize, uint32 flags, Area*& _area) TRACE("MemoryManager::_AllocateArea(%" B_PRIuSIZE ", %#" B_PRIx32 ")\n", chunkSize, flags); - if ((flags & CACHE_DONT_SLEEP) != 0) - return B_WOULD_BLOCK; - // TODO: Support CACHE_DONT_SLEEP for real! We already consider it in - // most cases below, but not for vm_create_null_area(). + ASSERT((flags & CACHE_DONT_LOCK_KERNEL_SPACE) == 0); mutex_unlock(&sLock); @@ -404,14 +407,11 @@ MemoryManager::_FreeArea(Area* area, uint32 flags) sAreaTable.RemoveUnchecked(area); writeLocker.Unlock(); - if (area->vmArea == NULL) { + if (area->vmArea == NULL || (flags & CACHE_DONT_LOCK_KERNEL_SPACE) != 0) { _push(sFreeAreas, area); return; } - // TODO: Do we need to handle CACHE_DONT_SLEEP here? Is delete_area() - // problematic? - mutex_unlock(&sLock); size_t reservedMemory = area->reserved_memory_for_mapping; @@ -468,14 +468,14 @@ MemoryManager::_MapChunk(VMArea* vmArea, addr_t address, size_t size, // reserve memory for the chunk size_t reservedMemory = size + reserveAdditionalMemory; status_t error = vm_try_reserve_memory(size, - (flags & CACHE_DONT_SLEEP) != 0 ? 0 : 1000000); + (flags & CACHE_DONT_WAIT_FOR_MEMORY) != 0 ? 0 : 1000000); if (error != B_OK) return error; // reserve the pages we need now size_t reservedPages = size / B_PAGE_SIZE + translationMap->MaxPagesNeededToMap(address, address + size - 1); - if ((flags & CACHE_DONT_SLEEP) != 0) { + if ((flags & CACHE_DONT_WAIT_FOR_MEMORY) != 0) { if (!vm_page_try_reserve_pages(reservedPages)) { vm_unreserve_memory(reservedMemory); return B_WOULD_BLOCK; diff --git a/src/system/kernel/slab/ObjectDepot.cpp b/src/system/kernel/slab/ObjectDepot.cpp index 0c6420bd3c..bc4c7cfd04 100644 --- a/src/system/kernel/slab/ObjectDepot.cpp +++ b/src/system/kernel/slab/ObjectDepot.cpp @@ -77,11 +77,10 @@ DepotMagazine::Push(void* object) static DepotMagazine* -alloc_magazine() +alloc_magazine(uint32 flags) { DepotMagazine* magazine = (DepotMagazine*)slab_internal_alloc( - sizeof(DepotMagazine) + kMagazineCapacity * sizeof(void*), - CACHE_DONT_SLEEP); + sizeof(DepotMagazine) + kMagazineCapacity * sizeof(void*), flags); if (magazine) { magazine->next = NULL; magazine->current_round = 0; @@ -264,7 +263,7 @@ object_depot_store(object_depot* depot, void* object, uint32 flags) interruptsLocker.Unlock(); readLocker.Unlock(); - DepotMagazine* magazine = alloc_magazine(); + DepotMagazine* magazine = alloc_magazine(flags); if (magazine == NULL) return 0; diff --git a/src/system/kernel/slab/Slab.cpp b/src/system/kernel/slab/Slab.cpp index 27d030f638..05699d73ec 100644 --- a/src/system/kernel/slab/Slab.cpp +++ b/src/system/kernel/slab/Slab.cpp @@ -312,7 +312,7 @@ object_cache_reserve_internal(ObjectCache* cache, size_t objectCount, if (cache->resize_entry_dont_wait != NULL) { resizeEntry = cache->resize_entry_dont_wait; } else if (cache->resize_entry_can_wait != NULL - && (flags & CACHE_DONT_SLEEP) == 0) { + && (flags & CACHE_DONT_WAIT_FOR_MEMORY) == 0) { resizeEntry = cache->resize_entry_can_wait; } else break; @@ -326,8 +326,9 @@ object_cache_reserve_internal(ObjectCache* cache, size_t objectCount, } // prepare the resize entry others can wait on - ObjectCacheResizeEntry*& resizeEntry = (flags & CACHE_DONT_SLEEP) != 0 - ? cache->resize_entry_dont_wait : cache->resize_entry_can_wait; + ObjectCacheResizeEntry*& resizeEntry + = (flags & CACHE_DONT_WAIT_FOR_MEMORY) != 0 + ? cache->resize_entry_dont_wait : cache->resize_entry_can_wait; ObjectCacheResizeEntry myResizeEntry; resizeEntry = &myResizeEntry; diff --git a/src/system/kernel/slab/allocator.cpp b/src/system/kernel/slab/allocator.cpp index cd00756484..2dec030c53 100644 --- a/src/system/kernel/slab/allocator.cpp +++ b/src/system/kernel/slab/allocator.cpp @@ -76,12 +76,15 @@ block_alloc(size_t size, uint32 flags) return object_cache_alloc(sBlockCaches[index], flags); // the allocation is too large for our object caches -- create an area + if ((flags & CACHE_DONT_LOCK_KERNEL_SPACE) != 0) + return NULL; + void* block; area_id area = create_area_etc(VMAddressSpace::KernelID(), "alloc'ed block", &block, B_ANY_KERNEL_ADDRESS, ROUNDUP(size, B_PAGE_SIZE), B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 0, - (flags & CACHE_DONT_SLEEP) != 0 ? CREATE_AREA_DONT_WAIT : 0); + (flags & CACHE_DONT_WAIT_FOR_MEMORY) != 0 ? CREATE_AREA_DONT_WAIT : 0); if (area < 0) return NULL; diff --git a/src/system/kernel/vm/VMAnonymousCache.cpp b/src/system/kernel/vm/VMAnonymousCache.cpp index 3aef26ac52..632106d124 100644 --- a/src/system/kernel/vm/VMAnonymousCache.cpp +++ b/src/system/kernel/vm/VMAnonymousCache.cpp @@ -779,7 +779,7 @@ VMAnonymousCache::_SwapBlockBuild(off_t startPageIndex, swap_block* swap = sSwapHashTable.Lookup(key); while (swap == NULL) { swap = (swap_block*)object_cache_alloc(sSwapBlockCache, - CACHE_DONT_SLEEP); + CACHE_DONT_WAIT_FOR_MEMORY | CACHE_DONT_LOCK_KERNEL_SPACE); if (swap == NULL) { // Wait a short time until memory is available again. locker.Unlock(); @@ -831,7 +831,8 @@ VMAnonymousCache::_SwapBlockFree(off_t startPageIndex, uint32 count) swap->used -= j; if (swap->used == 0) { sSwapHashTable.RemoveUnchecked(swap); - object_cache_free(sSwapBlockCache, swap, CACHE_DONT_SLEEP); + object_cache_free(sSwapBlockCache, swap, + CACHE_DONT_WAIT_FOR_MEMORY | CACHE_DONT_LOCK_KERNEL_SPACE); } } } @@ -1042,7 +1043,7 @@ VMAnonymousCache::_MergeSwapPages(VMAnonymousCache* source) // All swap pages have been freed -- we can discard the source swap // block. object_cache_free(sSwapBlockCache, sourceSwapBlock, - CACHE_DONT_SLEEP); + CACHE_DONT_WAIT_FOR_MEMORY | CACHE_DONT_LOCK_KERNEL_SPACE); } else if (swapBlock == NULL) { // We need to take over some of the source's swap pages and there's // no swap block in the consumer cache. Just take over the source @@ -1061,7 +1062,7 @@ VMAnonymousCache::_MergeSwapPages(VMAnonymousCache* source) } object_cache_free(sSwapBlockCache, sourceSwapBlock, - CACHE_DONT_SLEEP); + CACHE_DONT_WAIT_FOR_MEMORY | CACHE_DONT_LOCK_KERNEL_SPACE); } } } diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index 6ba58da8e2..f8bceb12d4 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -471,8 +471,11 @@ map_page(VMArea* area, vm_page* page, addr_t address, uint32 protection) if (area->wiring == B_NO_LOCK) { DEBUG_PAGE_ACCESS_CHECK(page); + bool isKernelSpace = area->address_space == VMAddressSpace::Kernel(); vm_page_mapping* mapping = (vm_page_mapping*)object_cache_alloc( - gPageMappingsObjectCache, CACHE_DONT_SLEEP); + gPageMappingsObjectCache, + CACHE_DONT_WAIT_FOR_MEMORY + | (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0)); if (mapping == NULL) return B_NO_MEMORY;