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
This commit is contained in:
@@ -14,16 +14,17 @@
|
|||||||
|
|
||||||
enum {
|
enum {
|
||||||
/* create_object_cache_etc flags */
|
/* create_object_cache_etc flags */
|
||||||
CACHE_NO_DEPOT = 1 << 0,
|
CACHE_NO_DEPOT = 1 << 0,
|
||||||
CACHE_UNLOCKED_PAGES = 1 << 1,
|
CACHE_UNLOCKED_PAGES = 1 << 1,
|
||||||
CACHE_LARGE_SLAB = 1 << 2,
|
CACHE_LARGE_SLAB = 1 << 2,
|
||||||
|
|
||||||
/* object_cache_alloc flags */
|
/* object_cache_{alloc,free}() flags */
|
||||||
CACHE_DONT_SLEEP = 1 << 8,
|
CACHE_DONT_WAIT_FOR_MEMORY = 1 << 8,
|
||||||
|
CACHE_DONT_LOCK_KERNEL_SPACE = 1 << 9,
|
||||||
|
|
||||||
/* internal */
|
/* internal */
|
||||||
CACHE_ALIGN_ON_SIZE = 1 << 30,
|
CACHE_ALIGN_ON_SIZE = 1 << 30,
|
||||||
CACHE_DURING_BOOT = 1 << 31
|
CACHE_DURING_BOOT = 1 << 31
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ObjectCache;
|
struct ObjectCache;
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ static int
|
|||||||
m_to_oc_flags(int how)
|
m_to_oc_flags(int how)
|
||||||
{
|
{
|
||||||
if (how & M_NOWAIT)
|
if (how & M_NOWAIT)
|
||||||
return CACHE_DONT_SLEEP;
|
return CACHE_DONT_WAIT_FOR_MEMORY;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -518,8 +518,12 @@ PPCVMTranslationMap::UnmapPage(VMArea* area, addr_t address)
|
|||||||
|
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
|
|
||||||
if (mapping != NULL)
|
if (mapping != NULL) {
|
||||||
object_cache_free(gPageMappingsObjectCache, mapping, CACHE_DONT_SLEEP);
|
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;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -628,8 +628,12 @@ X86VMTranslationMap::UnmapPage(VMArea* area, addr_t address)
|
|||||||
|
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
|
|
||||||
if (mapping != NULL)
|
if (mapping != NULL) {
|
||||||
object_cache_free(gPageMappingsObjectCache, mapping, CACHE_DONT_SLEEP);
|
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;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -738,8 +742,11 @@ X86VMTranslationMap::UnmapPages(VMArea* area, addr_t base, size_t size)
|
|||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
|
|
||||||
// free removed mappings
|
// 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())
|
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();
|
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())
|
while (vm_page_mapping* mapping = mappings.RemoveHead())
|
||||||
object_cache_free(gPageMappingsObjectCache, mapping, CACHE_DONT_SLEEP);
|
object_cache_free(gPageMappingsObjectCache, mapping, freeFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -140,7 +140,6 @@ MemoryManager::Allocate(ObjectCache* cache, uint32 flags, void*& _pages)
|
|||||||
} else
|
} else
|
||||||
chunk = _pop(area->unmappedFreeChunks);
|
chunk = _pop(area->unmappedFreeChunks);
|
||||||
|
|
||||||
|
|
||||||
if (++area->usedChunkCount == area->chunkCount) {
|
if (++area->usedChunkCount == area->chunkCount) {
|
||||||
areaPool->partialAreas.Remove(area);
|
areaPool->partialAreas.Remove(area);
|
||||||
areaPool->fullAreas.Add(area);
|
areaPool->fullAreas.Add(area);
|
||||||
@@ -160,7 +159,6 @@ MemoryManager::Allocate(ObjectCache* cache, uint32 flags, void*& _pages)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
chunk->cache = cache;
|
chunk->cache = cache;
|
||||||
_pages = (void*)chunkAddress;
|
_pages = (void*)chunkAddress;
|
||||||
|
|
||||||
@@ -246,6 +244,13 @@ MemoryManager::_AreaPoolFor(size_t chunkSize)
|
|||||||
/*static*/ status_t
|
/*static*/ status_t
|
||||||
MemoryManager::_GetPartialArea(AreaPool* areaPool, uint32 flags, Area*& _area)
|
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) {
|
while (true) {
|
||||||
Area* area = areaPool->partialAreas.Head();
|
Area* area = areaPool->partialAreas.Head();
|
||||||
if (area != NULL) {
|
if (area != NULL) {
|
||||||
@@ -259,7 +264,7 @@ MemoryManager::_GetPartialArea(AreaPool* areaPool, uint32 flags, Area*& _area)
|
|||||||
if (sAllocationEntryDontWait != NULL) {
|
if (sAllocationEntryDontWait != NULL) {
|
||||||
allocationEntry = sAllocationEntryDontWait;
|
allocationEntry = sAllocationEntryDontWait;
|
||||||
} else if (sAllocationEntryCanWait != NULL
|
} else if (sAllocationEntryCanWait != NULL
|
||||||
&& (flags & CACHE_DONT_SLEEP) == 0) {
|
&& (flags & CACHE_DONT_WAIT_FOR_MEMORY) == 0) {
|
||||||
allocationEntry = sAllocationEntryCanWait;
|
allocationEntry = sAllocationEntryCanWait;
|
||||||
} else
|
} else
|
||||||
break;
|
break;
|
||||||
@@ -273,8 +278,9 @@ MemoryManager::_GetPartialArea(AreaPool* areaPool, uint32 flags, Area*& _area)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// prepare the allocation entry others can wait on
|
// prepare the allocation entry others can wait on
|
||||||
AllocationEntry*& allocationEntry = (flags & CACHE_DONT_SLEEP) != 0
|
AllocationEntry*& allocationEntry
|
||||||
? sAllocationEntryDontWait : sAllocationEntryCanWait;
|
= (flags & CACHE_DONT_WAIT_FOR_MEMORY) != 0
|
||||||
|
? sAllocationEntryDontWait : sAllocationEntryCanWait;
|
||||||
|
|
||||||
AllocationEntry myResizeEntry;
|
AllocationEntry myResizeEntry;
|
||||||
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",
|
TRACE("MemoryManager::_AllocateArea(%" B_PRIuSIZE ", %#" B_PRIx32 ")\n",
|
||||||
chunkSize, flags);
|
chunkSize, flags);
|
||||||
|
|
||||||
if ((flags & CACHE_DONT_SLEEP) != 0)
|
ASSERT((flags & CACHE_DONT_LOCK_KERNEL_SPACE) == 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().
|
|
||||||
|
|
||||||
mutex_unlock(&sLock);
|
mutex_unlock(&sLock);
|
||||||
|
|
||||||
@@ -404,14 +407,11 @@ MemoryManager::_FreeArea(Area* area, uint32 flags)
|
|||||||
sAreaTable.RemoveUnchecked(area);
|
sAreaTable.RemoveUnchecked(area);
|
||||||
writeLocker.Unlock();
|
writeLocker.Unlock();
|
||||||
|
|
||||||
if (area->vmArea == NULL) {
|
if (area->vmArea == NULL || (flags & CACHE_DONT_LOCK_KERNEL_SPACE) != 0) {
|
||||||
_push(sFreeAreas, area);
|
_push(sFreeAreas, area);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Do we need to handle CACHE_DONT_SLEEP here? Is delete_area()
|
|
||||||
// problematic?
|
|
||||||
|
|
||||||
mutex_unlock(&sLock);
|
mutex_unlock(&sLock);
|
||||||
|
|
||||||
size_t reservedMemory = area->reserved_memory_for_mapping;
|
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
|
// reserve memory for the chunk
|
||||||
size_t reservedMemory = size + reserveAdditionalMemory;
|
size_t reservedMemory = size + reserveAdditionalMemory;
|
||||||
status_t error = vm_try_reserve_memory(size,
|
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)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
// reserve the pages we need now
|
// reserve the pages we need now
|
||||||
size_t reservedPages = size / B_PAGE_SIZE
|
size_t reservedPages = size / B_PAGE_SIZE
|
||||||
+ translationMap->MaxPagesNeededToMap(address, address + size - 1);
|
+ 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)) {
|
if (!vm_page_try_reserve_pages(reservedPages)) {
|
||||||
vm_unreserve_memory(reservedMemory);
|
vm_unreserve_memory(reservedMemory);
|
||||||
return B_WOULD_BLOCK;
|
return B_WOULD_BLOCK;
|
||||||
|
|||||||
@@ -77,11 +77,10 @@ DepotMagazine::Push(void* object)
|
|||||||
|
|
||||||
|
|
||||||
static DepotMagazine*
|
static DepotMagazine*
|
||||||
alloc_magazine()
|
alloc_magazine(uint32 flags)
|
||||||
{
|
{
|
||||||
DepotMagazine* magazine = (DepotMagazine*)slab_internal_alloc(
|
DepotMagazine* magazine = (DepotMagazine*)slab_internal_alloc(
|
||||||
sizeof(DepotMagazine) + kMagazineCapacity * sizeof(void*),
|
sizeof(DepotMagazine) + kMagazineCapacity * sizeof(void*), flags);
|
||||||
CACHE_DONT_SLEEP);
|
|
||||||
if (magazine) {
|
if (magazine) {
|
||||||
magazine->next = NULL;
|
magazine->next = NULL;
|
||||||
magazine->current_round = 0;
|
magazine->current_round = 0;
|
||||||
@@ -264,7 +263,7 @@ object_depot_store(object_depot* depot, void* object, uint32 flags)
|
|||||||
interruptsLocker.Unlock();
|
interruptsLocker.Unlock();
|
||||||
readLocker.Unlock();
|
readLocker.Unlock();
|
||||||
|
|
||||||
DepotMagazine* magazine = alloc_magazine();
|
DepotMagazine* magazine = alloc_magazine(flags);
|
||||||
if (magazine == NULL)
|
if (magazine == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|||||||
@@ -312,7 +312,7 @@ object_cache_reserve_internal(ObjectCache* cache, size_t objectCount,
|
|||||||
if (cache->resize_entry_dont_wait != NULL) {
|
if (cache->resize_entry_dont_wait != NULL) {
|
||||||
resizeEntry = cache->resize_entry_dont_wait;
|
resizeEntry = cache->resize_entry_dont_wait;
|
||||||
} else if (cache->resize_entry_can_wait != NULL
|
} 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;
|
resizeEntry = cache->resize_entry_can_wait;
|
||||||
} else
|
} else
|
||||||
break;
|
break;
|
||||||
@@ -326,8 +326,9 @@ object_cache_reserve_internal(ObjectCache* cache, size_t objectCount,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// prepare the resize entry others can wait on
|
// prepare the resize entry others can wait on
|
||||||
ObjectCacheResizeEntry*& resizeEntry = (flags & CACHE_DONT_SLEEP) != 0
|
ObjectCacheResizeEntry*& resizeEntry
|
||||||
? cache->resize_entry_dont_wait : cache->resize_entry_can_wait;
|
= (flags & CACHE_DONT_WAIT_FOR_MEMORY) != 0
|
||||||
|
? cache->resize_entry_dont_wait : cache->resize_entry_can_wait;
|
||||||
|
|
||||||
ObjectCacheResizeEntry myResizeEntry;
|
ObjectCacheResizeEntry myResizeEntry;
|
||||||
resizeEntry = &myResizeEntry;
|
resizeEntry = &myResizeEntry;
|
||||||
|
|||||||
@@ -76,12 +76,15 @@ block_alloc(size_t size, uint32 flags)
|
|||||||
return object_cache_alloc(sBlockCaches[index], flags);
|
return object_cache_alloc(sBlockCaches[index], flags);
|
||||||
|
|
||||||
// the allocation is too large for our object caches -- create an area
|
// the allocation is too large for our object caches -- create an area
|
||||||
|
if ((flags & CACHE_DONT_LOCK_KERNEL_SPACE) != 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
void* block;
|
void* block;
|
||||||
area_id area = create_area_etc(VMAddressSpace::KernelID(),
|
area_id area = create_area_etc(VMAddressSpace::KernelID(),
|
||||||
"alloc'ed block", &block, B_ANY_KERNEL_ADDRESS,
|
"alloc'ed block", &block, B_ANY_KERNEL_ADDRESS,
|
||||||
ROUNDUP(size, B_PAGE_SIZE), B_FULL_LOCK,
|
ROUNDUP(size, B_PAGE_SIZE), B_FULL_LOCK,
|
||||||
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 0,
|
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)
|
if (area < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|||||||
@@ -779,7 +779,7 @@ VMAnonymousCache::_SwapBlockBuild(off_t startPageIndex,
|
|||||||
swap_block* swap = sSwapHashTable.Lookup(key);
|
swap_block* swap = sSwapHashTable.Lookup(key);
|
||||||
while (swap == NULL) {
|
while (swap == NULL) {
|
||||||
swap = (swap_block*)object_cache_alloc(sSwapBlockCache,
|
swap = (swap_block*)object_cache_alloc(sSwapBlockCache,
|
||||||
CACHE_DONT_SLEEP);
|
CACHE_DONT_WAIT_FOR_MEMORY | CACHE_DONT_LOCK_KERNEL_SPACE);
|
||||||
if (swap == NULL) {
|
if (swap == NULL) {
|
||||||
// Wait a short time until memory is available again.
|
// Wait a short time until memory is available again.
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
@@ -831,7 +831,8 @@ VMAnonymousCache::_SwapBlockFree(off_t startPageIndex, uint32 count)
|
|||||||
swap->used -= j;
|
swap->used -= j;
|
||||||
if (swap->used == 0) {
|
if (swap->used == 0) {
|
||||||
sSwapHashTable.RemoveUnchecked(swap);
|
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
|
// All swap pages have been freed -- we can discard the source swap
|
||||||
// block.
|
// block.
|
||||||
object_cache_free(sSwapBlockCache, sourceSwapBlock,
|
object_cache_free(sSwapBlockCache, sourceSwapBlock,
|
||||||
CACHE_DONT_SLEEP);
|
CACHE_DONT_WAIT_FOR_MEMORY | CACHE_DONT_LOCK_KERNEL_SPACE);
|
||||||
} else if (swapBlock == NULL) {
|
} else if (swapBlock == NULL) {
|
||||||
// We need to take over some of the source's swap pages and there's
|
// 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
|
// 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,
|
object_cache_free(sSwapBlockCache, sourceSwapBlock,
|
||||||
CACHE_DONT_SLEEP);
|
CACHE_DONT_WAIT_FOR_MEMORY | CACHE_DONT_LOCK_KERNEL_SPACE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -471,8 +471,11 @@ map_page(VMArea* area, vm_page* page, addr_t address, uint32 protection)
|
|||||||
if (area->wiring == B_NO_LOCK) {
|
if (area->wiring == B_NO_LOCK) {
|
||||||
DEBUG_PAGE_ACCESS_CHECK(page);
|
DEBUG_PAGE_ACCESS_CHECK(page);
|
||||||
|
|
||||||
|
bool isKernelSpace = area->address_space == VMAddressSpace::Kernel();
|
||||||
vm_page_mapping* mapping = (vm_page_mapping*)object_cache_alloc(
|
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)
|
if (mapping == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user