Moved all knowledge of reserved areas from vm.cpp to VMAddressSpace. It's a

pure address space feature, so it should be handled there.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34491 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2009-12-04 13:33:25 +00:00
parent ef102a3599
commit 38a97b2c36
4 changed files with 214 additions and 148 deletions
+48 -17
View File
@@ -12,13 +12,14 @@
#include <OS.h>
#include <vm/vm_priv.h>
#include <vm/vm_translation_map.h>
#include <vm/VMArea.h>
struct VMAddressSpace {
public:
class Iterator;
class AreaIterator;
public:
VMAddressSpace(team_id id, addr_t base,
@@ -30,7 +31,7 @@ public:
team_id ID() const { return fID; }
addr_t Base() const { return fBase; }
size_t Size() const { return fSize; }
addr_t EndAddress() const { return fEndAddress; }
size_t FreeSpace() const { return fFreeSpace; }
bool IsBeingDeleted() const { return fDeleting; }
@@ -57,19 +58,26 @@ public:
void IncrementChangeCount()
{ fChangeCount++; }
VMArea* FirstArea() const
{ return fAreas.Head(); }
VMArea* NextArea(VMArea* area) const
{ return fAreas.GetNext(area); }
VMArea* FirstArea() const;
VMArea* LookupArea(addr_t address) const;
status_t InsertArea(void** _address, uint32 addressSpec,
addr_t size, VMArea* area);
void RemoveArea(VMArea* area);
bool CanResizeArea(VMArea* area, size_t newSize);
status_t ResizeArea(VMArea* area, size_t newSize);
status_t ResizeAreaHead(VMArea* area, size_t size);
status_t ResizeAreaTail(VMArea* area, size_t size);
inline Iterator GetIterator();
status_t ReserveAddressRange(void** _address,
uint32 addressSpec, size_t size,
uint32 flags);
status_t UnreserveAddressRange(addr_t address,
size_t size);
void UnreserveAllAddressRanges();
inline AreaIterator GetAreaIterator();
static status_t Create(team_id teamID, addr_t base, size_t size,
bool kernel,
@@ -108,7 +116,7 @@ private:
private:
VMAddressSpace* fHashTableLink;
addr_t fBase;
size_t fSize;
addr_t fEndAddress; // base + (size - 1)
size_t fFreeSpace;
rw_lock fLock;
team_id fID;
@@ -123,42 +131,65 @@ private:
};
class VMAddressSpace::Iterator {
class VMAddressSpace::AreaIterator {
public:
Iterator()
AreaIterator()
{
}
Iterator(VMAddressSpace* addressSpace)
AreaIterator(VMAddressSpace* addressSpace)
:
fIterator(addressSpace->fAreas.GetIterator())
{
_SkipReserved();
}
bool HasNext() const
{
return fIterator.HasNext();
return fNext != NULL;
}
VMArea* Next()
{
return fIterator.Next();
VMArea* result = fNext;
_SkipReserved();
return result;
}
void Rewind()
{
fIterator.Rewind();
_SkipReserved();
}
private:
VMAddressSpaceAreaList::Iterator fIterator;
void _SkipReserved()
{
while ((fNext = fIterator.Next()) != NULL
&& fNext->id == RESERVED_AREA_ID) {
}
}
private:
VMAddressSpaceAreaList::Iterator fIterator;
VMArea* fNext;
};
inline VMAddressSpace::Iterator
VMAddressSpace::GetIterator()
inline VMArea*
VMAddressSpace::FirstArea() const
{
return Iterator(this);
VMArea* area = fAreas.Head();
while (area != NULL && area->id == RESERVED_AREA_ID)
area = fAreas.GetNext(area);
return area;
}
inline VMAddressSpace::AreaIterator
VMAddressSpace::GetAreaIterator()
{
return AreaIterator(this);
}
+2 -1
View File
@@ -1304,7 +1304,8 @@ public:
{
// find the runtime loader debug area
VMArea* area;
for (VMAddressSpace::Iterator it = team->address_space->GetIterator();
for (VMAddressSpace::AreaIterator it
= team->address_space->GetAreaIterator();
(area = it.Next()) != NULL;) {
if (strcmp(area->name, RUNTIME_LOADER_DEBUG_AREA_NAME) == 0)
break;
+137 -8
View File
@@ -19,7 +19,6 @@
#include <heap.h>
#include <thread.h>
#include <vm/vm.h>
#include <vm/vm_priv.h>
#include <vm/VMArea.h>
@@ -88,7 +87,7 @@ VMAddressSpace::VMAddressSpace(team_id id, addr_t base, size_t size,
bool kernel)
:
fBase(base),
fSize(size),
fEndAddress(base + (size - 1)),
fFreeSpace(size),
fID(id),
fRefCount(1),
@@ -317,7 +316,7 @@ VMAddressSpace::InsertArea(void** _address, uint32 addressSpec, addr_t size,
case B_BASE_ADDRESS:
searchBase = (addr_t)*_address;
searchEnd = fBase + (fSize - 1);
searchEnd = fEndAddress;
break;
case B_ANY_ADDRESS:
@@ -328,7 +327,7 @@ VMAddressSpace::InsertArea(void** _address, uint32 addressSpec, addr_t size,
// completely (currently needs a userland address space!)
if (searchBase == USER_BASE)
searchBase = USER_BASE_ANY;
searchEnd = fBase + (fSize - 1);
searchEnd = fEndAddress;
break;
default:
@@ -361,6 +360,64 @@ VMAddressSpace::RemoveArea(VMArea* area)
}
bool
VMAddressSpace::CanResizeArea(VMArea* area, size_t newSize)
{
VMArea* next = fAreas.GetNext(area);
addr_t newEnd = area->Base() + (newSize - 1);
if (next == NULL) {
if (fEndAddress >= newEnd)
return true;
} else {
if (next->Base() > newEnd)
return true;
}
// If the area was created inside a reserved area, it can
// also be resized in that area
// TODO: if there is free space after the reserved area, it could
// be used as well...
if (next->id == RESERVED_AREA_ID && next->cache_offset <= area->Base()
&& next->Base() + (next->Size() - 1) >= newEnd) {
return true;
}
return false;
}
status_t
VMAddressSpace::ResizeArea(VMArea* area, size_t newSize)
{
addr_t newEnd = area->Base() + (newSize - 1);
VMArea* next = fAreas.GetNext(area);
if (next != NULL && next->Base() <= newEnd) {
if (next->id != RESERVED_AREA_ID
|| next->cache_offset > area->Base()
|| next->Base() + (next->Size() - 1) < newEnd) {
panic("resize situation for area %p has changed although we "
"should have the address space lock", area);
return B_ERROR;
}
// resize reserved area
addr_t offset = area->Base() + newSize - next->Base();
if (next->Size() <= offset) {
RemoveArea(next);
free(next);
} else {
status_t error = ResizeAreaHead(next, next->Size() - offset);
if (error != B_OK)
return error;
}
}
return ResizeAreaTail(area, newSize);
// TODO: In case of error we should undo the change to the reserved
// area.
}
status_t
VMAddressSpace::ResizeAreaHead(VMArea* area, size_t size)
{
@@ -388,6 +445,78 @@ VMAddressSpace::ResizeAreaTail(VMArea* area, size_t size)
}
status_t
VMAddressSpace::ReserveAddressRange(void** _address, uint32 addressSpec,
size_t size, uint32 flags)
{
// check to see if this address space has entered DELETE state
if (fDeleting) {
// okay, someone is trying to delete this address space now, so we
// can't insert the area, let's back out
return B_BAD_TEAM_ID;
}
VMArea* area = VMArea::CreateReserved(this, flags);
if (area == NULL)
return B_NO_MEMORY;
status_t status = InsertArea(_address, addressSpec, size, area);
if (status != B_OK) {
free(area);
return status;
}
area->cache_offset = area->Base();
// we cache the original base address here
Get();
return B_OK;
}
status_t
VMAddressSpace::UnreserveAddressRange(addr_t address, size_t size)
{
// check to see if this address space has entered DELETE state
if (fDeleting) {
// okay, someone is trying to delete this address space now, so we can't
// insert the area, so back out
return B_BAD_TEAM_ID;
}
// search area list and remove any matching reserved ranges
addr_t endAddress = address + (size - 1);
for (VMAddressSpaceAreaList::Iterator it = fAreas.GetIterator();
VMArea* area = it.Next();) {
// the area must be completely part of the reserved range
if (area->Base() + (area->Size() - 1) > endAddress)
break;
if (area->id == RESERVED_AREA_ID && area->Base() >= (addr_t)address) {
// remove reserved range
RemoveArea(area);
Put();
free(area);
}
}
return B_OK;
}
void
VMAddressSpace::UnreserveAllAddressRanges()
{
for (VMAddressSpaceAreaList::Iterator it = fAreas.GetIterator();
VMArea* area = it.Next();) {
if (area->id == RESERVED_AREA_ID) {
RemoveArea(area);
Put();
free(area);
}
}
}
void
VMAddressSpace::Dump() const
{
@@ -397,7 +526,7 @@ VMAddressSpace::Dump() const
kprintf("fault_count: %ld\n", fFaultCount);
kprintf("translation_map: %p\n", &fTranslationMap);
kprintf("base: 0x%lx\n", fBase);
kprintf("size: 0x%lx\n", fSize);
kprintf("end: 0x%lx\n", fEndAddress);
kprintf("change_count: 0x%lx\n", fChangeCount);
kprintf("area_hint: %p\n", fAreaHint);
@@ -505,7 +634,7 @@ VMAddressSpace::_InsertAreaSlot(addr_t start, addr_t size, addr_t end,
size, end, addressSpec, area));
// do some sanity checking
if (start < fBase || size == 0 || end > fBase + fSize - 1
if (start < fBase || size == 0 || end > fEndAddress
|| start + (size - 1) > end)
return B_BAD_ADDRESS;
@@ -753,7 +882,7 @@ VMAddressSpace::_DumpCommand(int argc, char** argv)
/*static*/ int
VMAddressSpace::_DumpListCommand(int argc, char** argv)
{
kprintf(" address id base size area count "
kprintf(" address id base end area count "
" area size\n");
AddressSpaceTable::Iterator it = sAddressSpaceTable.GetIterator();
@@ -769,7 +898,7 @@ VMAddressSpace::_DumpListCommand(int argc, char** argv)
}
}
kprintf("%p %6ld %#010lx %#10lx %10ld %10lld\n",
space, space->ID(), space->Base(), space->Size(), areaCount,
space, space->ID(), space->Base(), space->EndAddress(), areaCount,
areaSize);
}
+27 -122
View File
@@ -460,30 +460,26 @@ unmap_address_range(VMAddressSpace* addressSpace, addr_t address, addr_t size,
// Check, whether the caller is allowed to modify the concerned areas.
if (!kernel) {
for (VMAddressSpace::Iterator it = addressSpace->GetIterator();
for (VMAddressSpace::AreaIterator it = addressSpace->GetAreaIterator();
VMArea* area = it.Next();) {
if (area->id != RESERVED_AREA_ID) {
addr_t areaLast = area->Base() + (area->Size() - 1);
if (area->Base() < lastAddress && address < areaLast) {
if ((area->protection & B_KERNEL_AREA) != 0)
return B_NOT_ALLOWED;
}
addr_t areaLast = area->Base() + (area->Size() - 1);
if (area->Base() < lastAddress && address < areaLast) {
if ((area->protection & B_KERNEL_AREA) != 0)
return B_NOT_ALLOWED;
}
}
}
for (VMAddressSpace::Iterator it = addressSpace->GetIterator();
for (VMAddressSpace::AreaIterator it = addressSpace->GetAreaIterator();
VMArea* area = it.Next();) {
if (area->id != RESERVED_AREA_ID) {
addr_t areaLast = area->Base() + (area->Size() - 1);
if (area->Base() < lastAddress && address < areaLast) {
status_t error = cut_area(addressSpace, area, address,
lastAddress, NULL, kernel);
if (error != B_OK)
return error;
// Failing after already messing with areas is ugly, but we
// can't do anything about it.
}
addr_t areaLast = area->Base() + (area->Size() - 1);
if (area->Base() < lastAddress && address < areaLast) {
status_t error = cut_area(addressSpace, area, address,
lastAddress, NULL, kernel);
if (error != B_OK)
return error;
// Failing after already messing with areas is ugly, but we
// can't do anything about it.
}
}
@@ -651,29 +647,7 @@ vm_unreserve_address_range(team_id team, void* address, addr_t size)
if (!locker.IsLocked())
return B_BAD_TEAM_ID;
// check to see if this address space has entered DELETE state
if (locker.AddressSpace()->IsBeingDeleted()) {
// okay, someone is trying to delete this address space now, so we can't
// insert the area, so back out
return B_BAD_TEAM_ID;
}
// search area list and remove any matching reserved ranges
addr_t endAddress = (addr_t)address + (size - 1);
for (VMAddressSpace::Iterator it = locker.AddressSpace()->GetIterator();
VMArea* area = it.Next();) {
// the area must be completely part of the reserved range
if (area->Base() + (area->Size() - 1) > endAddress)
break;
if (area->id == RESERVED_AREA_ID && area->Base() >= (addr_t)address) {
// remove reserved range
locker.AddressSpace()->RemoveArea(area);
locker.AddressSpace()->Put();
free(area);
}
}
return B_OK;
return locker.AddressSpace()->UnreserveAddressRange((addr_t)address, size);
}
@@ -688,31 +662,8 @@ vm_reserve_address_range(team_id team, void** _address, uint32 addressSpec,
if (!locker.IsLocked())
return B_BAD_TEAM_ID;
// check to see if this address space has entered DELETE state
if (locker.AddressSpace()->IsBeingDeleted()) {
// okay, someone is trying to delete this address space now, so we
// can't insert the area, let's back out
return B_BAD_TEAM_ID;
}
VMArea* area = VMArea::CreateReserved(locker.AddressSpace(), flags);
if (area == NULL)
return B_NO_MEMORY;
status_t status = locker.AddressSpace()->InsertArea(_address, addressSpec,
size, area);
if (status != B_OK) {
free(area);
return status;
}
// the area is now reserved!
area->cache_offset = area->Base();
// we cache the original base address here
locker.AddressSpace()->Get();
return B_OK;
return locker.AddressSpace()->ReserveAddressRange(_address, addressSpec,
size, flags);
}
@@ -2907,16 +2858,7 @@ vm_delete_areas(struct VMAddressSpace* addressSpace)
addressSpace->WriteLock();
// remove all reserved areas in this address space
for (VMAddressSpace::Iterator it = addressSpace->GetIterator();
VMArea* area = it.Next();) {
if (area->id == RESERVED_AREA_ID) {
// just remove it
addressSpace->RemoveArea(area);
addressSpace->Put();
free(area);
}
}
addressSpace->UnreserveAllAddressRanges();
// delete all the areas in this address space
while (VMArea* area = addressSpace->FirstArea())
@@ -2995,12 +2937,13 @@ vm_free_unused_boot_loader_range(addr_t start, addr_t size)
map->ops->lock(map);
for (VMAddressSpace::Iterator it = VMAddressSpace::Kernel()->GetIterator();
for (VMAddressSpace::AreaIterator it
= VMAddressSpace::Kernel()->GetAreaIterator();
VMArea* area = it.Next();) {
addr_t areaStart = area->Base();
addr_t areaEnd = areaStart + (area->Size() - 1);
if (area->id == RESERVED_AREA_ID || areaEnd < start)
if (areaEnd < start)
continue;
if (areaStart > end) {
@@ -4251,23 +4194,10 @@ vm_resize_area(area_id areaID, size_t newSize, bool kernel)
if (oldSize < newSize) {
// We need to check if all areas of this cache can be resized
for (VMArea* current = cache->areas; current != NULL;
current = current->cache_next) {
VMArea* next = current->address_space->NextArea(current);
if (next != NULL && next->Base() <= (current->Base() + newSize)) {
// If the area was created inside a reserved area, it can
// also be resized in that area
// TODO: if there is free space after the reserved area, it could
// be used as well...
if (next->id == RESERVED_AREA_ID
&& next->cache_offset <= current->Base()
&& next->Base() - 1 + next->Size()
>= current->Base() - 1 + newSize)
continue;
if (!current->address_space->CanResizeArea(current, newSize))
return B_ERROR;
}
}
}
@@ -4282,35 +4212,12 @@ vm_resize_area(area_id areaID, size_t newSize, bool kernel)
for (VMArea* current = cache->areas; current != NULL;
current = current->cache_next) {
VMArea* next = current->address_space->NextArea(current);
if (next != NULL && next->Base() <= (current->Base() + newSize)) {
if (next->id == RESERVED_AREA_ID
&& next->cache_offset <= current->Base()
&& next->Base() - 1 + next->Size()
>= current->Base() - 1 + newSize) {
// resize reserved area
addr_t offset = current->Base() + newSize - next->Base();
if (next->Size() <= offset) {
next->address_space->RemoveArea(next);
free(next);
} else {
next->address_space->ResizeAreaHead(next,
next->Size() - offset);
}
} else {
panic("resize situation for area %p has changed although we "
"should have the address space lock", current);
status = B_ERROR;
break;
}
}
status = current->address_space->ResizeAreaTail(current, newSize);
status = current->address_space->ResizeArea(current, newSize);
if (status != B_OK)
break;
// We also need to unmap all pages beyond the new size, if the area has
// shrinked
// shrunk
if (newSize < oldSize) {
vm_unmap_pages(current, current->Base() + newSize, oldSize - newSize,
false);
@@ -4326,7 +4233,7 @@ vm_resize_area(area_id areaID, size_t newSize, bool kernel)
// This can fail, too, in which case we're seriously screwed.
for (VMArea* current = cache->areas; current != NULL;
current = current->cache_next) {
if (current->address_space->ResizeAreaTail(current, oldSize)
if (current->address_space->ResizeArea(current, oldSize)
!= B_OK) {
panic("vm_resize_area(): Failed and not being able to restore "
"original state.");
@@ -4792,11 +4699,9 @@ _get_next_area_info(team_id team, int32* cookie, area_info* info, size_t size)
return B_BAD_TEAM_ID;
VMArea* area;
for (VMAddressSpace::Iterator it = locker.AddressSpace()->GetIterator();
for (VMAddressSpace::AreaIterator it
= locker.AddressSpace()->GetAreaIterator();
(area = it.Next()) != NULL;) {
if (area->id == RESERVED_AREA_ID)
continue;
if (area->Base() > nextBase)
break;
}