kernel/vm: use DoublyLinkedList for VMCache areas list

Change-Id: I0c6a231f245fa542f5d90959755de1e6ba39eb8e
Reviewed-on: https://review.haiku-os.org/c/haiku/+/8685
Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
X512
2024-12-17 17:53:47 +00:00
committed by waddlesplash
parent 04c90835ac
commit 8ea4167e8b
8 changed files with 47 additions and 54 deletions
+7 -2
View File
@@ -119,8 +119,13 @@ public:
uint8* page_protections; uint8* page_protections;
struct VMAddressSpace* address_space; struct VMAddressSpace* address_space;
struct VMArea* cache_next;
struct VMArea* cache_prev; private:
DoublyLinkedListLink<VMArea> fCacheLink;
public:
typedef DoublyLinkedList<VMArea,
DoublyLinkedListMemberGetLink<VMArea, &VMArea::fCacheLink> > CacheList;
addr_t Base() const { return fBase; } addr_t Base() const { return fBase; }
size_t Size() const { return fSize; } size_t Size() const { return fSize; }
+2 -1
View File
@@ -15,6 +15,7 @@
#include <util/DoublyLinkedList.h> #include <util/DoublyLinkedList.h>
#include <vm/vm.h> #include <vm/vm.h>
#include <vm/vm_types.h> #include <vm/vm_types.h>
#include <vm/VMArea.h>
#include "kernel_debug_config.h" #include "kernel_debug_config.h"
@@ -188,7 +189,7 @@ protected:
virtual void DeleteObject() = 0; virtual void DeleteObject() = 0;
public: public:
VMArea* areas; VMArea::CacheList areas;
ConsumerList consumers; ConsumerList consumers;
// list of caches that use this cache as a source // list of caches that use this cache as a source
VMCachePagesTree pages; VMCachePagesTree pages;
+1 -1
View File
@@ -291,7 +291,7 @@ reserve_pages(file_cache_ref* ref, vm_page_reservation* reservation,
VMCache* cache = ref->cache; VMCache* cache = ref->cache;
cache->Lock(); cache->Lock();
if (cache->consumers.IsEmpty() && cache->areas == NULL if (cache->consumers.IsEmpty() && cache->areas.IsEmpty()
&& access_is_sequential(ref)) { && access_is_sequential(ref)) {
// we are not mapped, and we're accessed sequentially // we are not mapped, and we're accessed sequentially
@@ -524,9 +524,9 @@ MultiAddressSpaceLocker::AddAreaCacheAndLock(area_id areaID,
while (true) { while (true) {
// add all areas // add all areas
VMArea* firstArea = cache->areas; VMArea* firstArea = cache->areas.First();
for (VMArea* current = firstArea; current; for (VMArea* current = firstArea; current;
current = current->cache_next) { current = cache->areas.GetNext(current)) {
error = AddArea(current, error = AddArea(current,
current == area ? writeLockThisOne : writeLockOthers); current == area ? writeLockThisOne : writeLockOthers);
if (error != B_OK) { if (error != B_OK) {
@@ -558,7 +558,7 @@ MultiAddressSpaceLocker::AddAreaCacheAndLock(area_id areaID,
// If neither the area's cache has changed nor its area list we're // If neither the area's cache has changed nor its area list we're
// done. // done.
if (cache == oldCache && firstArea == cache->areas) { if (cache == oldCache && firstArea == cache->areas.First()) {
_area = area; _area = area;
if (_cache != NULL) if (_cache != NULL)
*_cache = cache; *_cache = cache;
+1 -3
View File
@@ -33,9 +33,7 @@ VMArea::VMArea(VMAddressSpace* addressSpace, uint32 wiring, uint32 protection)
cache_offset(0), cache_offset(0),
cache_type(0), cache_type(0),
page_protections(NULL), page_protections(NULL),
address_space(addressSpace), address_space(addressSpace)
cache_next(NULL),
cache_prev(NULL)
{ {
new (&mappings) VMAreaMappings; new (&mappings) VMAreaMappings;
} }
+11 -22
View File
@@ -611,7 +611,7 @@ VMCacheRef::VMCacheRef(VMCache* cache)
bool bool
VMCache::_IsMergeable() const VMCache::_IsMergeable() const
{ {
return areas == NULL && temporary && !unmergeable return areas.IsEmpty() && temporary && !unmergeable
&& !consumers.IsEmpty() && consumers.Head() == consumers.Tail(); && !consumers.IsEmpty() && consumers.Head() == consumers.Tail();
} }
@@ -636,7 +636,6 @@ VMCache::Init(uint32 cacheType, uint32 allocationFlags)
{ {
mutex_init(&fLock, "VMCache"); mutex_init(&fLock, "VMCache");
areas = NULL;
fRefCount = 1; fRefCount = 1;
source = NULL; source = NULL;
virtual_base = 0; virtual_base = 0;
@@ -677,7 +676,7 @@ VMCache::Init(uint32 cacheType, uint32 allocationFlags)
void void
VMCache::Delete() VMCache::Delete()
{ {
if (areas != NULL) if (!areas.IsEmpty())
panic("cache %p to be deleted still has areas", this); panic("cache %p to be deleted still has areas", this);
if (!consumers.IsEmpty()) if (!consumers.IsEmpty())
panic("cache %p to be deleted still has consumers", this); panic("cache %p to be deleted still has consumers", this);
@@ -980,15 +979,11 @@ status_t
VMCache::InsertAreaLocked(VMArea* area) VMCache::InsertAreaLocked(VMArea* area)
{ {
TRACE(("VMCache::InsertAreaLocked(cache %p, area %p)\n", this, area)); TRACE(("VMCache::InsertAreaLocked(cache %p, area %p)\n", this, area));
AssertLocked();
T(InsertArea(this, area)); T(InsertArea(this, area));
area->cache_next = areas; AssertLocked();
if (area->cache_next)
area->cache_next->cache_prev = area; areas.Insert(area, false);
area->cache_prev = NULL;
areas = area;
AcquireStoreRef(); AcquireStoreRef();
@@ -1011,12 +1006,7 @@ VMCache::RemoveArea(VMArea* area)
AutoLocker<VMCache> locker(this); AutoLocker<VMCache> locker(this);
if (area->cache_prev) areas.Remove(area);
area->cache_prev->cache_next = area->cache_next;
if (area->cache_next)
area->cache_next->cache_prev = area->cache_prev;
if (areas == area)
areas = area->cache_next;
return B_OK; return B_OK;
} }
@@ -1030,12 +1020,11 @@ VMCache::TransferAreas(VMCache* fromCache)
{ {
AssertLocked(); AssertLocked();
fromCache->AssertLocked(); fromCache->AssertLocked();
ASSERT(areas == NULL); ASSERT(areas.IsEmpty());
areas = fromCache->areas; areas.TakeFrom(&fromCache->areas);
fromCache->areas = NULL;
for (VMArea* area = areas; area != NULL; area = area->cache_next) { for (VMArea* area = areas.First(); area != NULL; area = areas.GetNext(area)) {
area->cache = this; area->cache = this;
AcquireRefLocked(); AcquireRefLocked();
fromCache->ReleaseRefLocked(); fromCache->ReleaseRefLocked();
@@ -1051,7 +1040,7 @@ VMCache::CountWritableAreas(VMArea* ignoreArea) const
{ {
uint32 count = 0; uint32 count = 0;
for (VMArea* area = areas; area != NULL; area = area->cache_next) { for (VMArea* area = areas.First(); area != NULL; area = areas.GetNext(area)) {
if (area != ignoreArea if (area != ignoreArea
&& (area->protection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) != 0) { && (area->protection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) != 0) {
count++; count++;
@@ -1471,7 +1460,7 @@ VMCache::Dump(bool showPages) const
#endif #endif
kprintf(" areas:\n"); kprintf(" areas:\n");
for (VMArea* area = areas; area != NULL; area = area->cache_next) { for (VMArea* area = areas.First(); area != NULL; area = areas.GetNext(area)) {
kprintf(" area 0x%" B_PRIx32 ", %s\n", area->id, area->name); kprintf(" area 0x%" B_PRIx32 ", %s\n", area->id, area->name);
kprintf("\tbase_addr: 0x%lx, size: 0x%lx\n", area->Base(), kprintf("\tbase_addr: 0x%lx, size: 0x%lx\n", area->Base(),
area->Size()); area->Size());
+16 -16
View File
@@ -780,7 +780,7 @@ cut_area(VMAddressSpace* addressSpace, VMArea* area, addr_t address,
// If no one else uses the area's cache and it's an anonymous cache, we can // If no one else uses the area's cache and it's an anonymous cache, we can
// resize or split it, too. // resize or split it, too.
bool onlyCacheUser = cache->areas == area && area->cache_next == NULL bool onlyCacheUser = cache->areas.First() == area && cache->areas.GetNext(area) == NULL
&& cache->consumers.IsEmpty() && area->cache_type == CACHE_TYPE_RAM; && cache->consumers.IsEmpty() && area->cache_type == CACHE_TYPE_RAM;
const addr_t oldSize = area->Size(); const addr_t oldSize = area->Size();
@@ -1110,7 +1110,7 @@ discard_area_range(VMArea* area, addr_t address, addr_t size)
// If someone else uses the area's cache or it's not an anonymous cache, we // If someone else uses the area's cache or it's not an anonymous cache, we
// can't discard. // can't discard.
VMCache* cache = vm_area_get_locked_cache(area); VMCache* cache = vm_area_get_locked_cache(area);
if (cache->areas != area || area->cache_next != NULL if (cache->areas.First() != area || VMArea::CacheList::GetNext(area) != NULL
|| !cache->consumers.IsEmpty() || cache->type != CACHE_TYPE_RAM) { || !cache->consumers.IsEmpty() || cache->type != CACHE_TYPE_RAM) {
return B_OK; return B_OK;
} }
@@ -2827,8 +2827,8 @@ vm_copy_on_write_area(VMCache* lowerCache,
DEBUG_PAGE_ACCESS_END(copiedPage); DEBUG_PAGE_ACCESS_END(copiedPage);
} else { } else {
// Change the protection of this page in all areas. // Change the protection of this page in all areas.
for (VMArea* tempArea = upperCache->areas; tempArea != NULL; for (VMArea* tempArea = upperCache->areas.First(); tempArea != NULL;
tempArea = tempArea->cache_next) { tempArea = upperCache->areas.GetNext(tempArea)) {
if (!is_page_in_area(tempArea, page)) if (!is_page_in_area(tempArea, page))
continue; continue;
@@ -2854,8 +2854,8 @@ vm_copy_on_write_area(VMCache* lowerCache,
ASSERT(lowerCache->WiredPagesCount() == 0); ASSERT(lowerCache->WiredPagesCount() == 0);
// just change the protection of all areas // just change the protection of all areas
for (VMArea* tempArea = upperCache->areas; tempArea != NULL; for (VMArea* tempArea = upperCache->areas.First(); tempArea != NULL;
tempArea = tempArea->cache_next) { tempArea = upperCache->areas.GetNext(tempArea)) {
if (tempArea->page_protections != NULL) { if (tempArea->page_protections != NULL) {
// Change the protection of all pages in this area. // Change the protection of all pages in this area.
VMTranslationMap* map = tempArea->address_space->TranslationMap(); VMTranslationMap* map = tempArea->address_space->TranslationMap();
@@ -3125,8 +3125,8 @@ vm_set_area_protection(team_id team, area_id areaID, uint32 newProtection,
// vm_copy_on_write_area(), all areas of the cache) doesn't have any // vm_copy_on_write_area(), all areas of the cache) doesn't have any
// wired ranges. // wired ranges.
if (!isWritable && becomesWritable && !cache->consumers.IsEmpty()) { if (!isWritable && becomesWritable && !cache->consumers.IsEmpty()) {
for (VMArea* otherArea = cache->areas; otherArea != NULL; for (VMArea* otherArea = cache->areas.First(); otherArea != NULL;
otherArea = otherArea->cache_next) { otherArea = cache->areas.GetNext(otherArea)) {
if (wait_if_area_is_wired(otherArea, &locker, &cacheLocker)) { if (wait_if_area_is_wired(otherArea, &locker, &cacheLocker)) {
restart = true; restart = true;
break; break;
@@ -4939,8 +4939,8 @@ vm_resize_area(area_id areaID, size_t newSize, bool kernel)
if (oldSize < newSize) { if (oldSize < newSize) {
// We need to check if all areas of this cache can be resized. // We need to check if all areas of this cache can be resized.
for (VMArea* current = cache->areas; current != NULL; for (VMArea* current = cache->areas.First(); current != NULL;
current = current->cache_next) { current = cache->areas.GetNext(current)) {
if (!current->address_space->CanResizeArea(current, newSize)) if (!current->address_space->CanResizeArea(current, newSize))
return B_ERROR; return B_ERROR;
anyKernelArea anyKernelArea
@@ -4949,8 +4949,8 @@ vm_resize_area(area_id areaID, size_t newSize, bool kernel)
} else { } else {
// We're shrinking the areas, so we must make sure the affected // We're shrinking the areas, so we must make sure the affected
// ranges are not wired. // ranges are not wired.
for (VMArea* current = cache->areas; current != NULL; for (VMArea* current = cache->areas.First(); current != NULL;
current = current->cache_next) { current = cache->areas.GetNext(current)) {
anyKernelArea anyKernelArea
|= current->address_space == VMAddressSpace::Kernel(); |= current->address_space == VMAddressSpace::Kernel();
@@ -4978,8 +4978,8 @@ vm_resize_area(area_id areaID, size_t newSize, bool kernel)
return status; return status;
} }
for (VMArea* current = cache->areas; current != NULL; for (VMArea* current = cache->areas.First(); current != NULL;
current = current->cache_next) { current = cache->areas.GetNext(current)) {
status = current->address_space->ResizeArea(current, newSize, status = current->address_space->ResizeArea(current, newSize,
allocationFlags); allocationFlags);
if (status != B_OK) if (status != B_OK)
@@ -5032,8 +5032,8 @@ vm_resize_area(area_id areaID, size_t newSize, bool kernel)
if (status != B_OK) { if (status != B_OK) {
// Something failed -- resize the areas back to their original size. // Something failed -- resize the areas back to their original size.
// This can fail, too, in which case we're seriously screwed. // This can fail, too, in which case we're seriously screwed.
for (VMArea* current = cache->areas; current != NULL; for (VMArea* current = cache->areas.First(); current != NULL;
current = current->cache_next) { current = cache->areas.GetNext(current)) {
if (current->address_space->ResizeArea(current, oldSize, if (current->address_space->ResizeArea(current, oldSize,
allocationFlags) != B_OK) { allocationFlags) != B_OK) {
panic("vm_resize_area(): Failed and not being able to restore " panic("vm_resize_area(): Failed and not being able to restore "
+6 -6
View File
@@ -331,13 +331,13 @@ dump_caches_recursively(VMCache* cache, cache_info& info, int level)
} }
// areas // areas
if (cache->areas != NULL) { if (!cache->areas.IsEmpty()) {
VMArea* area = cache->areas; VMArea* area = cache->areas.First();
kprintf(", areas: %" B_PRId32 " (%s, team: %" B_PRId32 ")", area->id, kprintf(", areas: %" B_PRId32 " (%s, team: %" B_PRId32 ")", area->id,
area->name, area->address_space->ID()); area->name, area->address_space->ID());
while (area->cache_next != NULL) { while (cache->areas.GetNext(area) != NULL) {
area = area->cache_next; area = cache->areas.GetNext(area);
kprintf(", %" B_PRId32, area->id); kprintf(", %" B_PRId32, area->id);
} }
} }
@@ -479,8 +479,8 @@ dump_area_struct(VMArea* area, bool mappings)
kprintf("cache:\t\t%p\n", area->cache); kprintf("cache:\t\t%p\n", area->cache);
kprintf("cache_type:\t%s\n", vm_cache_type_to_string(area->cache_type)); kprintf("cache_type:\t%s\n", vm_cache_type_to_string(area->cache_type));
kprintf("cache_offset:\t0x%" B_PRIx64 "\n", area->cache_offset); kprintf("cache_offset:\t0x%" B_PRIx64 "\n", area->cache_offset);
kprintf("cache_next:\t%p\n", area->cache_next); kprintf("cache_next:\t%p\n", VMArea::CacheList::GetNext(area));
kprintf("cache_prev:\t%p\n", area->cache_prev); kprintf("cache_prev:\t%p\n", VMArea::CacheList::GetPrevious(area));
VMAreaMappings::Iterator iterator = area->mappings.GetIterator(); VMAreaMappings::Iterator iterator = area->mappings.GetIterator();
if (mappings) { if (mappings) {