VMCache: Factor out a _FreePageRange method.
The code in the Resize and Rebase methods was identical except for the iterator. Change-Id: I9f6b3c2c09af0c26778215bd627fed030c4d46f1 Reviewed-on: https://review.haiku-os.org/c/haiku/+/2835 Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
57656b93b6
commit
428bc69ab8
@@ -215,6 +215,9 @@ private:
|
|||||||
void _MergeWithOnlyConsumer();
|
void _MergeWithOnlyConsumer();
|
||||||
void _RemoveConsumer(VMCache* consumer);
|
void _RemoveConsumer(VMCache* consumer);
|
||||||
|
|
||||||
|
bool _FreePageRange(VMCachePagesTree::Iterator it,
|
||||||
|
page_num_t* toPage);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int32 fRefCount;
|
int32 fRefCount;
|
||||||
mutex fLock;
|
mutex fLock;
|
||||||
|
|||||||
@@ -1111,6 +1111,46 @@ VMCache::SetMinimalCommitment(off_t commitment, int priority)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
VMCache::_FreePageRange(VMCachePagesTree::Iterator it,
|
||||||
|
page_num_t* toPage = NULL)
|
||||||
|
{
|
||||||
|
for (vm_page* page = it.Next();
|
||||||
|
page != NULL && (toPage == NULL || page->cache_offset < *toPage);
|
||||||
|
page = it.Next()) {
|
||||||
|
|
||||||
|
if (page->busy) {
|
||||||
|
if (page->busy_writing) {
|
||||||
|
// We cannot wait for the page to become available
|
||||||
|
// as we might cause a deadlock this way
|
||||||
|
page->busy_writing = false;
|
||||||
|
// this will notify the writer to free the page
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for page to become unbusy
|
||||||
|
WaitForPageEvents(page, PAGE_EVENT_NOT_BUSY, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove the page and put it into the free queue
|
||||||
|
DEBUG_PAGE_ACCESS_START(page);
|
||||||
|
vm_remove_all_page_mappings(page);
|
||||||
|
ASSERT(page->WiredCount() == 0);
|
||||||
|
// TODO: Find a real solution! If the page is wired
|
||||||
|
// temporarily (e.g. by lock_memory()), we actually must not
|
||||||
|
// unmap it!
|
||||||
|
RemovePage(page);
|
||||||
|
// Note: When iterating through a IteratableSplayTree
|
||||||
|
// removing the current node is safe.
|
||||||
|
|
||||||
|
vm_page_free(this, page);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! This function updates the size field of the cache.
|
/*! This function updates the size field of the cache.
|
||||||
If needed, it will free up all pages that don't belong to the cache anymore.
|
If needed, it will free up all pages that don't belong to the cache anymore.
|
||||||
The cache lock must be held when you call it.
|
The cache lock must be held when you call it.
|
||||||
@@ -1133,44 +1173,16 @@ VMCache::Resize(off_t newSize, int priority)
|
|||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
uint32 oldPageCount = (uint32)((virtual_end + B_PAGE_SIZE - 1)
|
page_num_t oldPageCount = (page_num_t)((virtual_end + B_PAGE_SIZE - 1)
|
||||||
|
>> PAGE_SHIFT);
|
||||||
|
page_num_t newPageCount = (page_num_t)((newSize + B_PAGE_SIZE - 1)
|
||||||
>> PAGE_SHIFT);
|
>> PAGE_SHIFT);
|
||||||
uint32 newPageCount = (uint32)((newSize + B_PAGE_SIZE - 1) >> PAGE_SHIFT);
|
|
||||||
|
|
||||||
if (newPageCount < oldPageCount) {
|
if (newPageCount < oldPageCount) {
|
||||||
// we need to remove all pages in the cache outside of the new virtual
|
// we need to remove all pages in the cache outside of the new virtual
|
||||||
// size
|
// size
|
||||||
for (VMCachePagesTree::Iterator it
|
while (_FreePageRange(pages.GetIterator(newPageCount, true, true)))
|
||||||
= pages.GetIterator(newPageCount, true, true);
|
;
|
||||||
vm_page* page = it.Next();) {
|
|
||||||
if (page->busy) {
|
|
||||||
if (page->busy_writing) {
|
|
||||||
// We cannot wait for the page to become available
|
|
||||||
// as we might cause a deadlock this way
|
|
||||||
page->busy_writing = false;
|
|
||||||
// this will notify the writer to free the page
|
|
||||||
} else {
|
|
||||||
// wait for page to become unbusy
|
|
||||||
WaitForPageEvents(page, PAGE_EVENT_NOT_BUSY, true);
|
|
||||||
|
|
||||||
// restart from the start of the list
|
|
||||||
it = pages.GetIterator(newPageCount, true, true);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove the page and put it into the free queue
|
|
||||||
DEBUG_PAGE_ACCESS_START(page);
|
|
||||||
vm_remove_all_page_mappings(page);
|
|
||||||
ASSERT(page->WiredCount() == 0);
|
|
||||||
// TODO: Find a real solution! If the page is wired
|
|
||||||
// temporarily (e.g. by lock_memory()), we actually must not
|
|
||||||
// unmap it!
|
|
||||||
RemovePage(page);
|
|
||||||
vm_page_free(this, page);
|
|
||||||
// Note: When iterating through a IteratableSplayTree
|
|
||||||
// removing the current node is safe.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual_end = newSize;
|
virtual_end = newSize;
|
||||||
@@ -1199,43 +1211,13 @@ VMCache::Rebase(off_t newBase, int priority)
|
|||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
uint32 basePage = (uint32)(newBase >> PAGE_SHIFT);
|
page_num_t basePage = (page_num_t)(newBase >> PAGE_SHIFT);
|
||||||
|
|
||||||
if (newBase > virtual_base) {
|
if (newBase > virtual_base) {
|
||||||
// we need to remove all pages in the cache outside of the new virtual
|
// we need to remove all pages in the cache outside of the new virtual
|
||||||
// size
|
// base
|
||||||
VMCachePagesTree::Iterator it = pages.GetIterator();
|
while (_FreePageRange(pages.GetIterator(), &basePage))
|
||||||
for (vm_page* page = it.Next();
|
;
|
||||||
page != NULL && page->cache_offset < basePage;
|
|
||||||
page = it.Next()) {
|
|
||||||
if (page->busy) {
|
|
||||||
if (page->busy_writing) {
|
|
||||||
// We cannot wait for the page to become available
|
|
||||||
// as we might cause a deadlock this way
|
|
||||||
page->busy_writing = false;
|
|
||||||
// this will notify the writer to free the page
|
|
||||||
} else {
|
|
||||||
// wait for page to become unbusy
|
|
||||||
WaitForPageEvents(page, PAGE_EVENT_NOT_BUSY, true);
|
|
||||||
|
|
||||||
// restart from the start of the list
|
|
||||||
it = pages.GetIterator();
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove the page and put it into the free queue
|
|
||||||
DEBUG_PAGE_ACCESS_START(page);
|
|
||||||
vm_remove_all_page_mappings(page);
|
|
||||||
ASSERT(page->WiredCount() == 0);
|
|
||||||
// TODO: Find a real solution! If the page is wired
|
|
||||||
// temporarily (e.g. by lock_memory()), we actually must not
|
|
||||||
// unmap it!
|
|
||||||
RemovePage(page);
|
|
||||||
vm_page_free(this, page);
|
|
||||||
// Note: When iterating through a IteratableSplayTree
|
|
||||||
// removing the current node is safe.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual_base = newBase;
|
virtual_base = newBase;
|
||||||
|
|||||||
Reference in New Issue
Block a user