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:
Ingo Weinhold
2010-01-22 21:19:23 +00:00
parent 86a0da42a5
commit 8d1316fd23
10 changed files with 64 additions and 42 deletions
+15 -15
View File
@@ -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;