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:
@@ -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; }
|
||||||
|
|||||||
@@ -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
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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 "
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user