Moved the three address space locker classes into a separate pair of
header/source files. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34451 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -9,6 +9,7 @@ KernelMergeObject kernel_vm.o :
|
|||||||
vm_daemons.cpp
|
vm_daemons.cpp
|
||||||
vm_page.cpp
|
vm_page.cpp
|
||||||
VMAddressSpace.cpp
|
VMAddressSpace.cpp
|
||||||
|
VMAddressSpaceLocking.cpp
|
||||||
VMAnonymousCache.cpp
|
VMAnonymousCache.cpp
|
||||||
VMAnonymousNoSwapCache.cpp
|
VMAnonymousNoSwapCache.cpp
|
||||||
VMArea.cpp
|
VMArea.cpp
|
||||||
|
|||||||
@@ -0,0 +1,549 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Copyright 2002-2009, Axel Dörfler, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "VMAddressSpaceLocking.h"
|
||||||
|
|
||||||
|
#include <AutoDeleter.h>
|
||||||
|
|
||||||
|
#include <vm/vm.h>
|
||||||
|
#include <vm/VMAddressSpace.h>
|
||||||
|
#include <vm/VMArea.h>
|
||||||
|
#include <vm/VMCache.h>
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - AddressSpaceLockerBase
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ VMAddressSpace*
|
||||||
|
AddressSpaceLockerBase::GetAddressSpaceByAreaID(area_id id)
|
||||||
|
{
|
||||||
|
VMAddressSpace* addressSpace = NULL;
|
||||||
|
|
||||||
|
VMAreaHash::ReadLock();
|
||||||
|
|
||||||
|
VMArea* area = VMAreaHash::LookupLocked(id);
|
||||||
|
if (area != NULL) {
|
||||||
|
addressSpace = area->address_space;
|
||||||
|
addressSpace->Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
VMAreaHash::ReadUnlock();
|
||||||
|
|
||||||
|
return addressSpace;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - AddressSpaceReadLocker
|
||||||
|
|
||||||
|
|
||||||
|
AddressSpaceReadLocker::AddressSpaceReadLocker(team_id team)
|
||||||
|
:
|
||||||
|
fSpace(NULL),
|
||||||
|
fLocked(false)
|
||||||
|
{
|
||||||
|
SetTo(team);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Takes over the reference of the address space, if \a getNewReference is
|
||||||
|
\c false.
|
||||||
|
*/
|
||||||
|
AddressSpaceReadLocker::AddressSpaceReadLocker(VMAddressSpace* space,
|
||||||
|
bool getNewReference)
|
||||||
|
:
|
||||||
|
fSpace(NULL),
|
||||||
|
fLocked(false)
|
||||||
|
{
|
||||||
|
SetTo(space, getNewReference);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AddressSpaceReadLocker::AddressSpaceReadLocker()
|
||||||
|
:
|
||||||
|
fSpace(NULL),
|
||||||
|
fLocked(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AddressSpaceReadLocker::~AddressSpaceReadLocker()
|
||||||
|
{
|
||||||
|
Unset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
AddressSpaceReadLocker::Unset()
|
||||||
|
{
|
||||||
|
Unlock();
|
||||||
|
if (fSpace != NULL)
|
||||||
|
fSpace->Put();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
AddressSpaceReadLocker::SetTo(team_id team)
|
||||||
|
{
|
||||||
|
fSpace = VMAddressSpace::Get(team);
|
||||||
|
if (fSpace == NULL)
|
||||||
|
return B_BAD_TEAM_ID;
|
||||||
|
|
||||||
|
fSpace->ReadLock();
|
||||||
|
fLocked = true;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Takes over the reference of the address space, if \a getNewReference is
|
||||||
|
\c false.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
AddressSpaceReadLocker::SetTo(VMAddressSpace* space, bool getNewReference)
|
||||||
|
{
|
||||||
|
fSpace = space;
|
||||||
|
|
||||||
|
if (getNewReference)
|
||||||
|
fSpace->Get();
|
||||||
|
|
||||||
|
fSpace->ReadLock();
|
||||||
|
fLocked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
AddressSpaceReadLocker::SetFromArea(area_id areaID, VMArea*& area)
|
||||||
|
{
|
||||||
|
fSpace = GetAddressSpaceByAreaID(areaID);
|
||||||
|
if (fSpace == NULL)
|
||||||
|
return B_BAD_TEAM_ID;
|
||||||
|
|
||||||
|
fSpace->ReadLock();
|
||||||
|
|
||||||
|
area = VMAreaHash::Lookup(areaID);
|
||||||
|
|
||||||
|
if (area == NULL || area->address_space != fSpace) {
|
||||||
|
fSpace->ReadUnlock();
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
fLocked = true;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
AddressSpaceReadLocker::Lock()
|
||||||
|
{
|
||||||
|
if (fLocked)
|
||||||
|
return true;
|
||||||
|
if (fSpace == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
fSpace->ReadLock();
|
||||||
|
fLocked = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
AddressSpaceReadLocker::Unlock()
|
||||||
|
{
|
||||||
|
if (fLocked) {
|
||||||
|
fSpace->ReadUnlock();
|
||||||
|
fLocked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - AddressSpaceWriteLocker
|
||||||
|
|
||||||
|
|
||||||
|
AddressSpaceWriteLocker::AddressSpaceWriteLocker(team_id team)
|
||||||
|
:
|
||||||
|
fSpace(NULL),
|
||||||
|
fLocked(false),
|
||||||
|
fDegraded(false)
|
||||||
|
{
|
||||||
|
SetTo(team);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AddressSpaceWriteLocker::AddressSpaceWriteLocker()
|
||||||
|
:
|
||||||
|
fSpace(NULL),
|
||||||
|
fLocked(false),
|
||||||
|
fDegraded(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AddressSpaceWriteLocker::~AddressSpaceWriteLocker()
|
||||||
|
{
|
||||||
|
Unset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
AddressSpaceWriteLocker::Unset()
|
||||||
|
{
|
||||||
|
Unlock();
|
||||||
|
if (fSpace != NULL)
|
||||||
|
fSpace->Put();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
AddressSpaceWriteLocker::SetTo(team_id team)
|
||||||
|
{
|
||||||
|
fSpace = VMAddressSpace::Get(team);
|
||||||
|
if (fSpace == NULL)
|
||||||
|
return B_BAD_TEAM_ID;
|
||||||
|
|
||||||
|
fSpace->WriteLock();
|
||||||
|
fLocked = true;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
AddressSpaceWriteLocker::SetFromArea(area_id areaID, VMArea*& area)
|
||||||
|
{
|
||||||
|
fSpace = GetAddressSpaceByAreaID(areaID);
|
||||||
|
if (fSpace == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
fSpace->WriteLock();
|
||||||
|
|
||||||
|
area = VMAreaHash::Lookup(areaID);
|
||||||
|
|
||||||
|
if (area == NULL || area->address_space != fSpace) {
|
||||||
|
fSpace->WriteUnlock();
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
fLocked = true;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
AddressSpaceWriteLocker::SetFromArea(team_id team, area_id areaID,
|
||||||
|
bool allowKernel, VMArea*& area)
|
||||||
|
{
|
||||||
|
VMAreaHash::ReadLock();
|
||||||
|
|
||||||
|
area = VMAreaHash::LookupLocked(areaID);
|
||||||
|
if (area != NULL
|
||||||
|
&& (area->address_space->ID() == team
|
||||||
|
|| (allowKernel && team == VMAddressSpace::KernelID()))) {
|
||||||
|
fSpace = area->address_space;
|
||||||
|
fSpace->Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
VMAreaHash::ReadUnlock();
|
||||||
|
|
||||||
|
if (fSpace == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
// Second try to get the area -- this time with the address space
|
||||||
|
// write lock held
|
||||||
|
|
||||||
|
fSpace->WriteLock();
|
||||||
|
|
||||||
|
area = VMAreaHash::Lookup(areaID);
|
||||||
|
|
||||||
|
if (area == NULL) {
|
||||||
|
fSpace->WriteUnlock();
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
fLocked = true;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
AddressSpaceWriteLocker::SetFromArea(team_id team, area_id areaID,
|
||||||
|
VMArea*& area)
|
||||||
|
{
|
||||||
|
return SetFromArea(team, areaID, false, area);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
AddressSpaceWriteLocker::Unlock()
|
||||||
|
{
|
||||||
|
if (fLocked) {
|
||||||
|
if (fDegraded)
|
||||||
|
fSpace->ReadUnlock();
|
||||||
|
else
|
||||||
|
fSpace->WriteUnlock();
|
||||||
|
fLocked = false;
|
||||||
|
fDegraded = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
AddressSpaceWriteLocker::DegradeToReadLock()
|
||||||
|
{
|
||||||
|
// TODO: the current R/W lock implementation just keeps the write lock here
|
||||||
|
fSpace->ReadLock();
|
||||||
|
fSpace->WriteUnlock();
|
||||||
|
fDegraded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - MultiAddressSpaceLocker
|
||||||
|
|
||||||
|
|
||||||
|
MultiAddressSpaceLocker::MultiAddressSpaceLocker()
|
||||||
|
:
|
||||||
|
fItems(NULL),
|
||||||
|
fCapacity(0),
|
||||||
|
fCount(0),
|
||||||
|
fLocked(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MultiAddressSpaceLocker::~MultiAddressSpaceLocker()
|
||||||
|
{
|
||||||
|
Unset();
|
||||||
|
free(fItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ int
|
||||||
|
MultiAddressSpaceLocker::_CompareItems(const void* _a, const void* _b)
|
||||||
|
{
|
||||||
|
lock_item* a = (lock_item*)_a;
|
||||||
|
lock_item* b = (lock_item*)_b;
|
||||||
|
return a->space->ID() - b->space->ID();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
MultiAddressSpaceLocker::_ResizeIfNeeded()
|
||||||
|
{
|
||||||
|
if (fCount == fCapacity) {
|
||||||
|
lock_item* items = (lock_item*)realloc(fItems,
|
||||||
|
(fCapacity + 4) * sizeof(lock_item));
|
||||||
|
if (items == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
fCapacity += 4;
|
||||||
|
fItems = items;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
MultiAddressSpaceLocker::_IndexOfAddressSpace(VMAddressSpace* space) const
|
||||||
|
{
|
||||||
|
for (int32 i = 0; i < fCount; i++) {
|
||||||
|
if (fItems[i].space == space)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
MultiAddressSpaceLocker::_AddAddressSpace(VMAddressSpace* space,
|
||||||
|
bool writeLock, VMAddressSpace** _space)
|
||||||
|
{
|
||||||
|
if (!space)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
int32 index = _IndexOfAddressSpace(space);
|
||||||
|
if (index < 0) {
|
||||||
|
if (!_ResizeIfNeeded()) {
|
||||||
|
space->Put();
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock_item& item = fItems[fCount++];
|
||||||
|
item.space = space;
|
||||||
|
item.write_lock = writeLock;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// one reference is enough
|
||||||
|
space->Put();
|
||||||
|
|
||||||
|
fItems[index].write_lock |= writeLock;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_space != NULL)
|
||||||
|
*_space = space;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
MultiAddressSpaceLocker::Unset()
|
||||||
|
{
|
||||||
|
Unlock();
|
||||||
|
|
||||||
|
for (int32 i = 0; i < fCount; i++)
|
||||||
|
fItems[i].space->Put();
|
||||||
|
|
||||||
|
fCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
MultiAddressSpaceLocker::Lock()
|
||||||
|
{
|
||||||
|
ASSERT(!fLocked);
|
||||||
|
|
||||||
|
qsort(fItems, fCount, sizeof(lock_item), &_CompareItems);
|
||||||
|
|
||||||
|
for (int32 i = 0; i < fCount; i++) {
|
||||||
|
status_t status;
|
||||||
|
if (fItems[i].write_lock)
|
||||||
|
status = fItems[i].space->WriteLock();
|
||||||
|
else
|
||||||
|
status = fItems[i].space->ReadLock();
|
||||||
|
|
||||||
|
if (status < B_OK) {
|
||||||
|
while (--i >= 0) {
|
||||||
|
if (fItems[i].write_lock)
|
||||||
|
fItems[i].space->WriteUnlock();
|
||||||
|
else
|
||||||
|
fItems[i].space->ReadUnlock();
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fLocked = true;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
MultiAddressSpaceLocker::Unlock()
|
||||||
|
{
|
||||||
|
if (!fLocked)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (int32 i = 0; i < fCount; i++) {
|
||||||
|
if (fItems[i].write_lock)
|
||||||
|
fItems[i].space->WriteUnlock();
|
||||||
|
else
|
||||||
|
fItems[i].space->ReadUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
fLocked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Adds all address spaces of the areas associated with the given area's cache,
|
||||||
|
locks them, and locks the cache (including a reference to it). It retries
|
||||||
|
until the situation is stable (i.e. the neither cache nor cache's areas
|
||||||
|
changed) or an error occurs.
|
||||||
|
*/
|
||||||
|
status_t
|
||||||
|
MultiAddressSpaceLocker::AddAreaCacheAndLock(area_id areaID,
|
||||||
|
bool writeLockThisOne, bool writeLockOthers, VMArea*& _area,
|
||||||
|
VMCache** _cache)
|
||||||
|
{
|
||||||
|
// remember the original state
|
||||||
|
int originalCount = fCount;
|
||||||
|
lock_item* originalItems = NULL;
|
||||||
|
if (fCount > 0) {
|
||||||
|
originalItems = new(nothrow) lock_item[fCount];
|
||||||
|
if (originalItems == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
memcpy(originalItems, fItems, fCount * sizeof(lock_item));
|
||||||
|
}
|
||||||
|
ArrayDeleter<lock_item> _(originalItems);
|
||||||
|
|
||||||
|
// get the cache
|
||||||
|
VMCache* cache;
|
||||||
|
VMArea* area;
|
||||||
|
status_t error;
|
||||||
|
{
|
||||||
|
AddressSpaceReadLocker locker;
|
||||||
|
error = locker.SetFromArea(areaID, area);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
cache = vm_area_get_locked_cache(area);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// add all areas
|
||||||
|
VMArea* firstArea = cache->areas;
|
||||||
|
for (VMArea* current = firstArea; current;
|
||||||
|
current = current->cache_next) {
|
||||||
|
error = AddArea(current->id,
|
||||||
|
current == area ? writeLockThisOne : writeLockOthers);
|
||||||
|
if (error != B_OK) {
|
||||||
|
vm_area_put_locked_cache(cache);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unlock the cache and attempt to lock the address spaces
|
||||||
|
vm_area_put_locked_cache(cache);
|
||||||
|
|
||||||
|
error = Lock();
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
// lock the cache again and check whether anything has changed
|
||||||
|
|
||||||
|
// check whether the area is gone in the meantime
|
||||||
|
area = VMAreaHash::Lookup(areaID);
|
||||||
|
|
||||||
|
if (area == NULL) {
|
||||||
|
Unlock();
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// lock the cache
|
||||||
|
VMCache* oldCache = cache;
|
||||||
|
cache = vm_area_get_locked_cache(area);
|
||||||
|
|
||||||
|
// If neither the area's cache has changed nor its area list we're
|
||||||
|
// done.
|
||||||
|
if (cache == oldCache && firstArea == cache->areas) {
|
||||||
|
_area = area;
|
||||||
|
if (_cache != NULL)
|
||||||
|
*_cache = cache;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore the original state and try again.
|
||||||
|
|
||||||
|
// Unlock the address spaces, but keep the cache locked for the next
|
||||||
|
// iteration.
|
||||||
|
Unlock();
|
||||||
|
|
||||||
|
// Get an additional reference to the original address spaces.
|
||||||
|
for (int32 i = 0; i < originalCount; i++)
|
||||||
|
originalItems[i].space->Get();
|
||||||
|
|
||||||
|
// Release all references to the current address spaces.
|
||||||
|
for (int32 i = 0; i < fCount; i++)
|
||||||
|
fItems[i].space->Put();
|
||||||
|
|
||||||
|
// Copy over the original state.
|
||||||
|
fCount = originalCount;
|
||||||
|
if (originalItems != NULL)
|
||||||
|
memcpy(fItems, originalItems, fCount * sizeof(lock_item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Copyright 2002-2009, Axel Dörfler, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef VM_ADDRESS_SPACE_LOCKING_H
|
||||||
|
#define VM_ADDRESS_SPACE_LOCKING_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <OS.h>
|
||||||
|
|
||||||
|
#include <vm/VMAddressSpace.h>
|
||||||
|
|
||||||
|
|
||||||
|
struct VMAddressSpace;
|
||||||
|
struct VMArea;
|
||||||
|
struct VMCache;
|
||||||
|
|
||||||
|
|
||||||
|
class AddressSpaceLockerBase {
|
||||||
|
public:
|
||||||
|
static VMAddressSpace* GetAddressSpaceByAreaID(area_id id);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class AddressSpaceReadLocker : private AddressSpaceLockerBase {
|
||||||
|
public:
|
||||||
|
AddressSpaceReadLocker(team_id team);
|
||||||
|
AddressSpaceReadLocker(VMAddressSpace* space,
|
||||||
|
bool getNewReference);
|
||||||
|
AddressSpaceReadLocker();
|
||||||
|
~AddressSpaceReadLocker();
|
||||||
|
|
||||||
|
status_t SetTo(team_id team);
|
||||||
|
void SetTo(VMAddressSpace* space,
|
||||||
|
bool getNewReference);
|
||||||
|
status_t SetFromArea(area_id areaID, VMArea*& area);
|
||||||
|
|
||||||
|
bool IsLocked() const { return fLocked; }
|
||||||
|
bool Lock();
|
||||||
|
void Unlock();
|
||||||
|
|
||||||
|
void Unset();
|
||||||
|
|
||||||
|
VMAddressSpace* AddressSpace() const { return fSpace; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
VMAddressSpace* fSpace;
|
||||||
|
bool fLocked;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class AddressSpaceWriteLocker : private AddressSpaceLockerBase {
|
||||||
|
public:
|
||||||
|
AddressSpaceWriteLocker(team_id team);
|
||||||
|
AddressSpaceWriteLocker();
|
||||||
|
~AddressSpaceWriteLocker();
|
||||||
|
|
||||||
|
status_t SetTo(team_id team);
|
||||||
|
status_t SetFromArea(area_id areaID, VMArea*& area);
|
||||||
|
status_t SetFromArea(team_id team, area_id areaID,
|
||||||
|
bool allowKernel, VMArea*& area);
|
||||||
|
status_t SetFromArea(team_id team, area_id areaID,
|
||||||
|
VMArea*& area);
|
||||||
|
|
||||||
|
bool IsLocked() const { return fLocked; }
|
||||||
|
void Unlock();
|
||||||
|
|
||||||
|
void DegradeToReadLock();
|
||||||
|
void Unset();
|
||||||
|
|
||||||
|
VMAddressSpace* AddressSpace() const { return fSpace; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
VMAddressSpace* fSpace;
|
||||||
|
bool fLocked;
|
||||||
|
bool fDegraded;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class MultiAddressSpaceLocker : private AddressSpaceLockerBase {
|
||||||
|
public:
|
||||||
|
MultiAddressSpaceLocker();
|
||||||
|
~MultiAddressSpaceLocker();
|
||||||
|
|
||||||
|
inline status_t AddTeam(team_id team, bool writeLock,
|
||||||
|
VMAddressSpace** _space = NULL);
|
||||||
|
inline status_t AddArea(area_id area, bool writeLock,
|
||||||
|
VMAddressSpace** _space = NULL);
|
||||||
|
|
||||||
|
status_t AddAreaCacheAndLock(area_id areaID,
|
||||||
|
bool writeLockThisOne, bool writeLockOthers,
|
||||||
|
VMArea*& _area, VMCache** _cache = NULL);
|
||||||
|
|
||||||
|
status_t Lock();
|
||||||
|
void Unlock();
|
||||||
|
bool IsLocked() const { return fLocked; }
|
||||||
|
|
||||||
|
void Unset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct lock_item {
|
||||||
|
VMAddressSpace* space;
|
||||||
|
bool write_lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool _ResizeIfNeeded();
|
||||||
|
int32 _IndexOfAddressSpace(VMAddressSpace* space)
|
||||||
|
const;
|
||||||
|
status_t _AddAddressSpace(VMAddressSpace* space,
|
||||||
|
bool writeLock, VMAddressSpace** _space);
|
||||||
|
|
||||||
|
static int _CompareItems(const void* _a, const void* _b);
|
||||||
|
|
||||||
|
lock_item* fItems;
|
||||||
|
int32 fCapacity;
|
||||||
|
int32 fCount;
|
||||||
|
bool fLocked;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline status_t
|
||||||
|
MultiAddressSpaceLocker::AddTeam(team_id team, bool writeLock,
|
||||||
|
VMAddressSpace** _space)
|
||||||
|
{
|
||||||
|
return _AddAddressSpace(VMAddressSpace::Get(team), writeLock, _space);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline status_t
|
||||||
|
MultiAddressSpaceLocker::AddArea(area_id area, bool writeLock,
|
||||||
|
VMAddressSpace** _space)
|
||||||
|
{
|
||||||
|
return _AddAddressSpace(GetAddressSpaceByAreaID(area), writeLock, _space);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // VM_ADDRESS_SPACE_LOCKING_H
|
||||||
+1
-637
@@ -50,6 +50,7 @@
|
|||||||
#include <vm/VMArea.h>
|
#include <vm/VMArea.h>
|
||||||
#include <vm/VMCache.h>
|
#include <vm/VMCache.h>
|
||||||
|
|
||||||
|
#include "VMAddressSpaceLocking.h"
|
||||||
#include "VMAnonymousCache.h"
|
#include "VMAnonymousCache.h"
|
||||||
#include "IORequest.h"
|
#include "IORequest.h"
|
||||||
|
|
||||||
@@ -68,95 +69,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
class AddressSpaceReadLocker {
|
|
||||||
public:
|
|
||||||
AddressSpaceReadLocker(team_id team);
|
|
||||||
AddressSpaceReadLocker(VMAddressSpace* space, bool getNewReference);
|
|
||||||
AddressSpaceReadLocker();
|
|
||||||
~AddressSpaceReadLocker();
|
|
||||||
|
|
||||||
status_t SetTo(team_id team);
|
|
||||||
void SetTo(VMAddressSpace* space, bool getNewReference);
|
|
||||||
status_t SetFromArea(area_id areaID, VMArea*& area);
|
|
||||||
|
|
||||||
bool IsLocked() const { return fLocked; }
|
|
||||||
bool Lock();
|
|
||||||
void Unlock();
|
|
||||||
|
|
||||||
void Unset();
|
|
||||||
|
|
||||||
VMAddressSpace* AddressSpace() { return fSpace; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
VMAddressSpace* fSpace;
|
|
||||||
bool fLocked;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AddressSpaceWriteLocker {
|
|
||||||
public:
|
|
||||||
AddressSpaceWriteLocker(team_id team);
|
|
||||||
AddressSpaceWriteLocker();
|
|
||||||
~AddressSpaceWriteLocker();
|
|
||||||
|
|
||||||
status_t SetTo(team_id team);
|
|
||||||
status_t SetFromArea(area_id areaID, VMArea*& area);
|
|
||||||
status_t SetFromArea(team_id team, area_id areaID, bool allowKernel,
|
|
||||||
VMArea*& area);
|
|
||||||
status_t SetFromArea(team_id team, area_id areaID, VMArea*& area);
|
|
||||||
|
|
||||||
bool IsLocked() const { return fLocked; }
|
|
||||||
void Unlock();
|
|
||||||
|
|
||||||
void DegradeToReadLock();
|
|
||||||
void Unset();
|
|
||||||
|
|
||||||
VMAddressSpace* AddressSpace() { return fSpace; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
VMAddressSpace* fSpace;
|
|
||||||
bool fLocked;
|
|
||||||
bool fDegraded;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MultiAddressSpaceLocker {
|
|
||||||
public:
|
|
||||||
MultiAddressSpaceLocker();
|
|
||||||
~MultiAddressSpaceLocker();
|
|
||||||
|
|
||||||
inline status_t AddTeam(team_id team, bool writeLock,
|
|
||||||
VMAddressSpace** _space = NULL);
|
|
||||||
inline status_t AddArea(area_id area, bool writeLock,
|
|
||||||
VMAddressSpace** _space = NULL);
|
|
||||||
|
|
||||||
status_t AddAreaCacheAndLock(area_id areaID, bool writeLockThisOne,
|
|
||||||
bool writeLockOthers, VMArea*& _area, VMCache** _cache = NULL);
|
|
||||||
|
|
||||||
status_t Lock();
|
|
||||||
void Unlock();
|
|
||||||
bool IsLocked() const { return fLocked; }
|
|
||||||
|
|
||||||
void Unset();
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct lock_item {
|
|
||||||
VMAddressSpace* space;
|
|
||||||
bool write_lock;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool _ResizeIfNeeded();
|
|
||||||
int32 _IndexOfAddressSpace(VMAddressSpace* space) const;
|
|
||||||
status_t _AddAddressSpace(VMAddressSpace* space, bool writeLock,
|
|
||||||
VMAddressSpace** _space);
|
|
||||||
|
|
||||||
static int _CompareItems(const void* _a, const void* _b);
|
|
||||||
|
|
||||||
lock_item* fItems;
|
|
||||||
int32 fCapacity;
|
|
||||||
int32 fCount;
|
|
||||||
bool fLocked;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class AreaCacheLocking {
|
class AreaCacheLocking {
|
||||||
public:
|
public:
|
||||||
inline bool Lock(VMCache* lockable)
|
inline bool Lock(VMCache* lockable)
|
||||||
@@ -216,7 +128,6 @@ static cache_info* sCacheInfoTable;
|
|||||||
|
|
||||||
// function declarations
|
// function declarations
|
||||||
static void delete_area(VMAddressSpace* addressSpace, VMArea* area);
|
static void delete_area(VMAddressSpace* addressSpace, VMArea* area);
|
||||||
static VMAddressSpace* get_address_space_by_area_id(area_id id);
|
|
||||||
static status_t vm_soft_fault(VMAddressSpace* addressSpace, addr_t address,
|
static status_t vm_soft_fault(VMAddressSpace* addressSpace, addr_t address,
|
||||||
bool isWrite, bool isUser);
|
bool isWrite, bool isUser);
|
||||||
static status_t map_backing_store(VMAddressSpace* addressSpace,
|
static status_t map_backing_store(VMAddressSpace* addressSpace,
|
||||||
@@ -231,534 +142,6 @@ static size_t sKernelAddressSpaceLeft = KERNEL_SIZE;
|
|||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
AddressSpaceReadLocker::AddressSpaceReadLocker(team_id team)
|
|
||||||
:
|
|
||||||
fSpace(NULL),
|
|
||||||
fLocked(false)
|
|
||||||
{
|
|
||||||
SetTo(team);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*! Takes over the reference of the address space, if \a getNewReference is
|
|
||||||
\c false.
|
|
||||||
*/
|
|
||||||
AddressSpaceReadLocker::AddressSpaceReadLocker(VMAddressSpace* space,
|
|
||||||
bool getNewReference)
|
|
||||||
:
|
|
||||||
fSpace(NULL),
|
|
||||||
fLocked(false)
|
|
||||||
{
|
|
||||||
SetTo(space, getNewReference);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
AddressSpaceReadLocker::AddressSpaceReadLocker()
|
|
||||||
:
|
|
||||||
fSpace(NULL),
|
|
||||||
fLocked(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
AddressSpaceReadLocker::~AddressSpaceReadLocker()
|
|
||||||
{
|
|
||||||
Unset();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
AddressSpaceReadLocker::Unset()
|
|
||||||
{
|
|
||||||
Unlock();
|
|
||||||
if (fSpace != NULL)
|
|
||||||
fSpace->Put();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
AddressSpaceReadLocker::SetTo(team_id team)
|
|
||||||
{
|
|
||||||
fSpace = VMAddressSpace::Get(team);
|
|
||||||
if (fSpace == NULL)
|
|
||||||
return B_BAD_TEAM_ID;
|
|
||||||
|
|
||||||
fSpace->ReadLock();
|
|
||||||
fLocked = true;
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*! Takes over the reference of the address space, if \a getNewReference is
|
|
||||||
\c false.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
AddressSpaceReadLocker::SetTo(VMAddressSpace* space, bool getNewReference)
|
|
||||||
{
|
|
||||||
fSpace = space;
|
|
||||||
|
|
||||||
if (getNewReference)
|
|
||||||
fSpace->Get();
|
|
||||||
|
|
||||||
fSpace->ReadLock();
|
|
||||||
fLocked = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
AddressSpaceReadLocker::SetFromArea(area_id areaID, VMArea*& area)
|
|
||||||
{
|
|
||||||
fSpace = get_address_space_by_area_id(areaID);
|
|
||||||
if (fSpace == NULL)
|
|
||||||
return B_BAD_TEAM_ID;
|
|
||||||
|
|
||||||
fSpace->ReadLock();
|
|
||||||
|
|
||||||
area = VMAreaHash::Lookup(areaID);
|
|
||||||
|
|
||||||
if (area == NULL || area->address_space != fSpace) {
|
|
||||||
fSpace->ReadUnlock();
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
fLocked = true;
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
AddressSpaceReadLocker::Lock()
|
|
||||||
{
|
|
||||||
if (fLocked)
|
|
||||||
return true;
|
|
||||||
if (fSpace == NULL)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
fSpace->ReadLock();
|
|
||||||
fLocked = true;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
AddressSpaceReadLocker::Unlock()
|
|
||||||
{
|
|
||||||
if (fLocked) {
|
|
||||||
fSpace->ReadUnlock();
|
|
||||||
fLocked = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
|
||||||
|
|
||||||
|
|
||||||
AddressSpaceWriteLocker::AddressSpaceWriteLocker(team_id team)
|
|
||||||
:
|
|
||||||
fSpace(NULL),
|
|
||||||
fLocked(false),
|
|
||||||
fDegraded(false)
|
|
||||||
{
|
|
||||||
SetTo(team);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
AddressSpaceWriteLocker::AddressSpaceWriteLocker()
|
|
||||||
:
|
|
||||||
fSpace(NULL),
|
|
||||||
fLocked(false),
|
|
||||||
fDegraded(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
AddressSpaceWriteLocker::~AddressSpaceWriteLocker()
|
|
||||||
{
|
|
||||||
Unset();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
AddressSpaceWriteLocker::Unset()
|
|
||||||
{
|
|
||||||
Unlock();
|
|
||||||
if (fSpace != NULL)
|
|
||||||
fSpace->Put();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
AddressSpaceWriteLocker::SetTo(team_id team)
|
|
||||||
{
|
|
||||||
fSpace = VMAddressSpace::Get(team);
|
|
||||||
if (fSpace == NULL)
|
|
||||||
return B_BAD_TEAM_ID;
|
|
||||||
|
|
||||||
fSpace->WriteLock();
|
|
||||||
fLocked = true;
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
AddressSpaceWriteLocker::SetFromArea(area_id areaID, VMArea*& area)
|
|
||||||
{
|
|
||||||
fSpace = get_address_space_by_area_id(areaID);
|
|
||||||
if (fSpace == NULL)
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
|
|
||||||
fSpace->WriteLock();
|
|
||||||
|
|
||||||
area = VMAreaHash::Lookup(areaID);
|
|
||||||
|
|
||||||
if (area == NULL || area->address_space != fSpace) {
|
|
||||||
fSpace->WriteUnlock();
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
fLocked = true;
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
AddressSpaceWriteLocker::SetFromArea(team_id team, area_id areaID,
|
|
||||||
bool allowKernel, VMArea*& area)
|
|
||||||
{
|
|
||||||
VMAreaHash::ReadLock();
|
|
||||||
|
|
||||||
area = VMAreaHash::LookupLocked(areaID);
|
|
||||||
if (area != NULL
|
|
||||||
&& (area->address_space->ID() == team
|
|
||||||
|| (allowKernel && team == VMAddressSpace::KernelID()))) {
|
|
||||||
fSpace = area->address_space;
|
|
||||||
fSpace->Get();
|
|
||||||
}
|
|
||||||
|
|
||||||
VMAreaHash::ReadUnlock();
|
|
||||||
|
|
||||||
if (fSpace == NULL)
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
|
|
||||||
// Second try to get the area -- this time with the address space
|
|
||||||
// write lock held
|
|
||||||
|
|
||||||
fSpace->WriteLock();
|
|
||||||
|
|
||||||
area = VMAreaHash::Lookup(areaID);
|
|
||||||
|
|
||||||
if (area == NULL) {
|
|
||||||
fSpace->WriteUnlock();
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
fLocked = true;
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
AddressSpaceWriteLocker::SetFromArea(team_id team, area_id areaID,
|
|
||||||
VMArea*& area)
|
|
||||||
{
|
|
||||||
return SetFromArea(team, areaID, false, area);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
AddressSpaceWriteLocker::Unlock()
|
|
||||||
{
|
|
||||||
if (fLocked) {
|
|
||||||
if (fDegraded)
|
|
||||||
fSpace->ReadUnlock();
|
|
||||||
else
|
|
||||||
fSpace->WriteUnlock();
|
|
||||||
fLocked = false;
|
|
||||||
fDegraded = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
AddressSpaceWriteLocker::DegradeToReadLock()
|
|
||||||
{
|
|
||||||
// TODO: the current R/W lock implementation just keeps the write lock here
|
|
||||||
fSpace->ReadLock();
|
|
||||||
fSpace->WriteUnlock();
|
|
||||||
fDegraded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
|
||||||
|
|
||||||
|
|
||||||
MultiAddressSpaceLocker::MultiAddressSpaceLocker()
|
|
||||||
:
|
|
||||||
fItems(NULL),
|
|
||||||
fCapacity(0),
|
|
||||||
fCount(0),
|
|
||||||
fLocked(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
MultiAddressSpaceLocker::~MultiAddressSpaceLocker()
|
|
||||||
{
|
|
||||||
Unset();
|
|
||||||
free(fItems);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*static*/ int
|
|
||||||
MultiAddressSpaceLocker::_CompareItems(const void* _a, const void* _b)
|
|
||||||
{
|
|
||||||
lock_item* a = (lock_item*)_a;
|
|
||||||
lock_item* b = (lock_item*)_b;
|
|
||||||
return a->space->ID() - b->space->ID();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
MultiAddressSpaceLocker::_ResizeIfNeeded()
|
|
||||||
{
|
|
||||||
if (fCount == fCapacity) {
|
|
||||||
lock_item* items = (lock_item*)realloc(fItems,
|
|
||||||
(fCapacity + 4) * sizeof(lock_item));
|
|
||||||
if (items == NULL)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
fCapacity += 4;
|
|
||||||
fItems = items;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int32
|
|
||||||
MultiAddressSpaceLocker::_IndexOfAddressSpace(VMAddressSpace* space) const
|
|
||||||
{
|
|
||||||
for (int32 i = 0; i < fCount; i++) {
|
|
||||||
if (fItems[i].space == space)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
MultiAddressSpaceLocker::_AddAddressSpace(VMAddressSpace* space,
|
|
||||||
bool writeLock, VMAddressSpace** _space)
|
|
||||||
{
|
|
||||||
if (!space)
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
|
|
||||||
int32 index = _IndexOfAddressSpace(space);
|
|
||||||
if (index < 0) {
|
|
||||||
if (!_ResizeIfNeeded()) {
|
|
||||||
space->Put();
|
|
||||||
return B_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock_item& item = fItems[fCount++];
|
|
||||||
item.space = space;
|
|
||||||
item.write_lock = writeLock;
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// one reference is enough
|
|
||||||
space->Put();
|
|
||||||
|
|
||||||
fItems[index].write_lock |= writeLock;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_space != NULL)
|
|
||||||
*_space = space;
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline status_t
|
|
||||||
MultiAddressSpaceLocker::AddTeam(team_id team, bool writeLock,
|
|
||||||
VMAddressSpace** _space)
|
|
||||||
{
|
|
||||||
return _AddAddressSpace(VMAddressSpace::Get(team), writeLock,
|
|
||||||
_space);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline status_t
|
|
||||||
MultiAddressSpaceLocker::AddArea(area_id area, bool writeLock,
|
|
||||||
VMAddressSpace** _space)
|
|
||||||
{
|
|
||||||
return _AddAddressSpace(get_address_space_by_area_id(area), writeLock,
|
|
||||||
_space);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
MultiAddressSpaceLocker::Unset()
|
|
||||||
{
|
|
||||||
Unlock();
|
|
||||||
|
|
||||||
for (int32 i = 0; i < fCount; i++)
|
|
||||||
fItems[i].space->Put();
|
|
||||||
|
|
||||||
fCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
MultiAddressSpaceLocker::Lock()
|
|
||||||
{
|
|
||||||
ASSERT(!fLocked);
|
|
||||||
|
|
||||||
qsort(fItems, fCount, sizeof(lock_item), &_CompareItems);
|
|
||||||
|
|
||||||
for (int32 i = 0; i < fCount; i++) {
|
|
||||||
status_t status;
|
|
||||||
if (fItems[i].write_lock)
|
|
||||||
status = fItems[i].space->WriteLock();
|
|
||||||
else
|
|
||||||
status = fItems[i].space->ReadLock();
|
|
||||||
|
|
||||||
if (status < B_OK) {
|
|
||||||
while (--i >= 0) {
|
|
||||||
if (fItems[i].write_lock)
|
|
||||||
fItems[i].space->WriteUnlock();
|
|
||||||
else
|
|
||||||
fItems[i].space->ReadUnlock();
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fLocked = true;
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
MultiAddressSpaceLocker::Unlock()
|
|
||||||
{
|
|
||||||
if (!fLocked)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (int32 i = 0; i < fCount; i++) {
|
|
||||||
if (fItems[i].write_lock)
|
|
||||||
fItems[i].space->WriteUnlock();
|
|
||||||
else
|
|
||||||
fItems[i].space->ReadUnlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
fLocked = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*! Adds all address spaces of the areas associated with the given area's cache,
|
|
||||||
locks them, and locks the cache (including a reference to it). It retries
|
|
||||||
until the situation is stable (i.e. the neither cache nor cache's areas
|
|
||||||
changed) or an error occurs.
|
|
||||||
*/
|
|
||||||
status_t
|
|
||||||
MultiAddressSpaceLocker::AddAreaCacheAndLock(area_id areaID,
|
|
||||||
bool writeLockThisOne, bool writeLockOthers, VMArea*& _area,
|
|
||||||
VMCache** _cache)
|
|
||||||
{
|
|
||||||
// remember the original state
|
|
||||||
int originalCount = fCount;
|
|
||||||
lock_item* originalItems = NULL;
|
|
||||||
if (fCount > 0) {
|
|
||||||
originalItems = new(nothrow) lock_item[fCount];
|
|
||||||
if (originalItems == NULL)
|
|
||||||
return B_NO_MEMORY;
|
|
||||||
memcpy(originalItems, fItems, fCount * sizeof(lock_item));
|
|
||||||
}
|
|
||||||
ArrayDeleter<lock_item> _(originalItems);
|
|
||||||
|
|
||||||
// get the cache
|
|
||||||
VMCache* cache;
|
|
||||||
VMArea* area;
|
|
||||||
status_t error;
|
|
||||||
{
|
|
||||||
AddressSpaceReadLocker locker;
|
|
||||||
error = locker.SetFromArea(areaID, area);
|
|
||||||
if (error != B_OK)
|
|
||||||
return error;
|
|
||||||
|
|
||||||
cache = vm_area_get_locked_cache(area);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
// add all areas
|
|
||||||
VMArea* firstArea = cache->areas;
|
|
||||||
for (VMArea* current = firstArea; current;
|
|
||||||
current = current->cache_next) {
|
|
||||||
error = AddArea(current->id,
|
|
||||||
current == area ? writeLockThisOne : writeLockOthers);
|
|
||||||
if (error != B_OK) {
|
|
||||||
vm_area_put_locked_cache(cache);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// unlock the cache and attempt to lock the address spaces
|
|
||||||
vm_area_put_locked_cache(cache);
|
|
||||||
|
|
||||||
error = Lock();
|
|
||||||
if (error != B_OK)
|
|
||||||
return error;
|
|
||||||
|
|
||||||
// lock the cache again and check whether anything has changed
|
|
||||||
|
|
||||||
// check whether the area is gone in the meantime
|
|
||||||
area = VMAreaHash::Lookup(areaID);
|
|
||||||
|
|
||||||
if (area == NULL) {
|
|
||||||
Unlock();
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// lock the cache
|
|
||||||
VMCache* oldCache = cache;
|
|
||||||
cache = vm_area_get_locked_cache(area);
|
|
||||||
|
|
||||||
// If neither the area's cache has changed nor its area list we're
|
|
||||||
// done.
|
|
||||||
if (cache == oldCache && firstArea == cache->areas) {
|
|
||||||
_area = area;
|
|
||||||
if (_cache != NULL)
|
|
||||||
*_cache = cache;
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore the original state and try again.
|
|
||||||
|
|
||||||
// Unlock the address spaces, but keep the cache locked for the next
|
|
||||||
// iteration.
|
|
||||||
Unlock();
|
|
||||||
|
|
||||||
// Get an additional reference to the original address spaces.
|
|
||||||
for (int32 i = 0; i < originalCount; i++)
|
|
||||||
originalItems[i].space->Get();
|
|
||||||
|
|
||||||
// Release all references to the current address spaces.
|
|
||||||
for (int32 i = 0; i < fCount; i++)
|
|
||||||
fItems[i].space->Put();
|
|
||||||
|
|
||||||
// Copy over the original state.
|
|
||||||
fCount = originalCount;
|
|
||||||
if (originalItems != NULL)
|
|
||||||
memcpy(fItems, originalItems, fCount * sizeof(lock_item));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
|
||||||
|
|
||||||
|
|
||||||
#if VM_PAGE_FAULT_TRACING
|
#if VM_PAGE_FAULT_TRACING
|
||||||
|
|
||||||
namespace VMPageFaultTracing {
|
namespace VMPageFaultTracing {
|
||||||
@@ -882,25 +265,6 @@ private:
|
|||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
static VMAddressSpace*
|
|
||||||
get_address_space_by_area_id(area_id id)
|
|
||||||
{
|
|
||||||
VMAddressSpace* addressSpace = NULL;
|
|
||||||
|
|
||||||
VMAreaHash::ReadLock();
|
|
||||||
|
|
||||||
VMArea* area = VMAreaHash::LookupLocked(id);
|
|
||||||
if (area != NULL) {
|
|
||||||
addressSpace = area->address_space;
|
|
||||||
addressSpace->Get();
|
|
||||||
}
|
|
||||||
|
|
||||||
VMAreaHash::ReadUnlock();
|
|
||||||
|
|
||||||
return addressSpace;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//! You need to have the address space locked when calling this function
|
//! You need to have the address space locked when calling this function
|
||||||
static VMArea*
|
static VMArea*
|
||||||
lookup_area(VMAddressSpace* addressSpace, area_id id)
|
lookup_area(VMAddressSpace* addressSpace, area_id id)
|
||||||
|
|||||||
Reference in New Issue
Block a user