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 <OS.h>
#include <vm/vm_priv.h>
#include <vm/vm_translation_map.h> #include <vm/vm_translation_map.h>
#include <vm/VMArea.h> #include <vm/VMArea.h>
struct VMAddressSpace { struct VMAddressSpace {
public: public:
class Iterator; class AreaIterator;
public: public:
VMAddressSpace(team_id id, addr_t base, VMAddressSpace(team_id id, addr_t base,
@@ -30,7 +31,7 @@ public:
team_id ID() const { return fID; } team_id ID() const { return fID; }
addr_t Base() const { return fBase; } addr_t Base() const { return fBase; }
size_t Size() const { return fSize; } addr_t EndAddress() const { return fEndAddress; }
size_t FreeSpace() const { return fFreeSpace; } size_t FreeSpace() const { return fFreeSpace; }
bool IsBeingDeleted() const { return fDeleting; } bool IsBeingDeleted() const { return fDeleting; }
@@ -57,19 +58,26 @@ public:
void IncrementChangeCount() void IncrementChangeCount()
{ fChangeCount++; } { fChangeCount++; }
VMArea* FirstArea() const VMArea* FirstArea() const;
{ return fAreas.Head(); }
VMArea* NextArea(VMArea* area) const
{ return fAreas.GetNext(area); }
VMArea* LookupArea(addr_t address) const; VMArea* LookupArea(addr_t address) const;
status_t InsertArea(void** _address, uint32 addressSpec, status_t InsertArea(void** _address, uint32 addressSpec,
addr_t size, VMArea* area); addr_t size, VMArea* area);
void RemoveArea(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 ResizeAreaHead(VMArea* area, size_t size);
status_t ResizeAreaTail(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, static status_t Create(team_id teamID, addr_t base, size_t size,
bool kernel, bool kernel,
@@ -108,7 +116,7 @@ private:
private: private:
VMAddressSpace* fHashTableLink; VMAddressSpace* fHashTableLink;
addr_t fBase; addr_t fBase;
size_t fSize; addr_t fEndAddress; // base + (size - 1)
size_t fFreeSpace; size_t fFreeSpace;
rw_lock fLock; rw_lock fLock;
team_id fID; team_id fID;
@@ -123,42 +131,65 @@ private:
}; };
class VMAddressSpace::Iterator { class VMAddressSpace::AreaIterator {
public: public:
Iterator() AreaIterator()
{ {
} }
Iterator(VMAddressSpace* addressSpace) AreaIterator(VMAddressSpace* addressSpace)
: :
fIterator(addressSpace->fAreas.GetIterator()) fIterator(addressSpace->fAreas.GetIterator())
{ {
_SkipReserved();
} }
bool HasNext() const bool HasNext() const
{ {
return fIterator.HasNext(); return fNext != NULL;
} }
VMArea* Next() VMArea* Next()
{ {
return fIterator.Next(); VMArea* result = fNext;
_SkipReserved();
return result;
} }
void Rewind() void Rewind()
{ {
fIterator.Rewind(); fIterator.Rewind();
_SkipReserved();
} }
private: 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 inline VMArea*
VMAddressSpace::GetIterator() 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 // find the runtime loader debug area
VMArea* area; VMArea* area;
for (VMAddressSpace::Iterator it = team->address_space->GetIterator(); for (VMAddressSpace::AreaIterator it
= team->address_space->GetAreaIterator();
(area = it.Next()) != NULL;) { (area = it.Next()) != NULL;) {
if (strcmp(area->name, RUNTIME_LOADER_DEBUG_AREA_NAME) == 0) if (strcmp(area->name, RUNTIME_LOADER_DEBUG_AREA_NAME) == 0)
break; break;
+137 -8
View File
@@ -19,7 +19,6 @@
#include <heap.h> #include <heap.h>
#include <thread.h> #include <thread.h>
#include <vm/vm.h> #include <vm/vm.h>
#include <vm/vm_priv.h>
#include <vm/VMArea.h> #include <vm/VMArea.h>
@@ -88,7 +87,7 @@ VMAddressSpace::VMAddressSpace(team_id id, addr_t base, size_t size,
bool kernel) bool kernel)
: :
fBase(base), fBase(base),
fSize(size), fEndAddress(base + (size - 1)),
fFreeSpace(size), fFreeSpace(size),
fID(id), fID(id),
fRefCount(1), fRefCount(1),
@@ -317,7 +316,7 @@ VMAddressSpace::InsertArea(void** _address, uint32 addressSpec, addr_t size,
case B_BASE_ADDRESS: case B_BASE_ADDRESS:
searchBase = (addr_t)*_address; searchBase = (addr_t)*_address;
searchEnd = fBase + (fSize - 1); searchEnd = fEndAddress;
break; break;
case B_ANY_ADDRESS: case B_ANY_ADDRESS:
@@ -328,7 +327,7 @@ VMAddressSpace::InsertArea(void** _address, uint32 addressSpec, addr_t size,
// completely (currently needs a userland address space!) // completely (currently needs a userland address space!)
if (searchBase == USER_BASE) if (searchBase == USER_BASE)
searchBase = USER_BASE_ANY; searchBase = USER_BASE_ANY;
searchEnd = fBase + (fSize - 1); searchEnd = fEndAddress;
break; break;
default: 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 status_t
VMAddressSpace::ResizeAreaHead(VMArea* area, size_t size) 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 void
VMAddressSpace::Dump() const VMAddressSpace::Dump() const
{ {
@@ -397,7 +526,7 @@ VMAddressSpace::Dump() const
kprintf("fault_count: %ld\n", fFaultCount); kprintf("fault_count: %ld\n", fFaultCount);
kprintf("translation_map: %p\n", &fTranslationMap); kprintf("translation_map: %p\n", &fTranslationMap);
kprintf("base: 0x%lx\n", fBase); 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("change_count: 0x%lx\n", fChangeCount);
kprintf("area_hint: %p\n", fAreaHint); 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)); size, end, addressSpec, area));
// do some sanity checking // do some sanity checking
if (start < fBase || size == 0 || end > fBase + fSize - 1 if (start < fBase || size == 0 || end > fEndAddress
|| start + (size - 1) > end) || start + (size - 1) > end)
return B_BAD_ADDRESS; return B_BAD_ADDRESS;
@@ -753,7 +882,7 @@ VMAddressSpace::_DumpCommand(int argc, char** argv)
/*static*/ int /*static*/ int
VMAddressSpace::_DumpListCommand(int argc, char** argv) VMAddressSpace::_DumpListCommand(int argc, char** argv)
{ {
kprintf(" address id base size area count " kprintf(" address id base end area count "
" area size\n"); " area size\n");
AddressSpaceTable::Iterator it = sAddressSpaceTable.GetIterator(); AddressSpaceTable::Iterator it = sAddressSpaceTable.GetIterator();
@@ -769,7 +898,7 @@ VMAddressSpace::_DumpListCommand(int argc, char** argv)
} }
} }
kprintf("%p %6ld %#010lx %#10lx %10ld %10lld\n", 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); 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. // Check, whether the caller is allowed to modify the concerned areas.
if (!kernel) { if (!kernel) {
for (VMAddressSpace::Iterator it = addressSpace->GetIterator(); for (VMAddressSpace::AreaIterator it = addressSpace->GetAreaIterator();
VMArea* area = it.Next();) { VMArea* area = it.Next();) {
if (area->id != RESERVED_AREA_ID) { addr_t areaLast = area->Base() + (area->Size() - 1);
addr_t areaLast = area->Base() + (area->Size() - 1); if (area->Base() < lastAddress && address < areaLast) {
if (area->Base() < lastAddress && address < areaLast) { if ((area->protection & B_KERNEL_AREA) != 0)
if ((area->protection & B_KERNEL_AREA) != 0) return B_NOT_ALLOWED;
return B_NOT_ALLOWED;
}
} }
} }
} }
for (VMAddressSpace::Iterator it = addressSpace->GetIterator(); for (VMAddressSpace::AreaIterator it = addressSpace->GetAreaIterator();
VMArea* area = it.Next();) { VMArea* area = it.Next();) {
if (area->id != RESERVED_AREA_ID) { addr_t areaLast = area->Base() + (area->Size() - 1);
addr_t areaLast = area->Base() + (area->Size() - 1); if (area->Base() < lastAddress && address < areaLast) {
if (area->Base() < lastAddress && address < areaLast) { status_t error = cut_area(addressSpace, area, address,
status_t error = cut_area(addressSpace, area, address, lastAddress, NULL, kernel);
lastAddress, NULL, kernel); if (error != B_OK)
if (error != B_OK) return error;
return error; // Failing after already messing with areas is ugly, but we
// Failing after already messing with areas is ugly, but we // can't do anything about it.
// 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()) if (!locker.IsLocked())
return B_BAD_TEAM_ID; return B_BAD_TEAM_ID;
// check to see if this address space has entered DELETE state return locker.AddressSpace()->UnreserveAddressRange((addr_t)address, size);
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;
} }
@@ -688,31 +662,8 @@ vm_reserve_address_range(team_id team, void** _address, uint32 addressSpec,
if (!locker.IsLocked()) if (!locker.IsLocked())
return B_BAD_TEAM_ID; return B_BAD_TEAM_ID;
// check to see if this address space has entered DELETE state return locker.AddressSpace()->ReserveAddressRange(_address, addressSpec,
if (locker.AddressSpace()->IsBeingDeleted()) { size, flags);
// 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;
} }
@@ -2907,16 +2858,7 @@ vm_delete_areas(struct VMAddressSpace* addressSpace)
addressSpace->WriteLock(); addressSpace->WriteLock();
// remove all reserved areas in this address space // remove all reserved areas in this address space
addressSpace->UnreserveAllAddressRanges();
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);
}
}
// delete all the areas in this address space // delete all the areas in this address space
while (VMArea* area = addressSpace->FirstArea()) 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); map->ops->lock(map);
for (VMAddressSpace::Iterator it = VMAddressSpace::Kernel()->GetIterator(); for (VMAddressSpace::AreaIterator it
= VMAddressSpace::Kernel()->GetAreaIterator();
VMArea* area = it.Next();) { VMArea* area = it.Next();) {
addr_t areaStart = area->Base(); addr_t areaStart = area->Base();
addr_t areaEnd = areaStart + (area->Size() - 1); addr_t areaEnd = areaStart + (area->Size() - 1);
if (area->id == RESERVED_AREA_ID || areaEnd < start) if (areaEnd < start)
continue; continue;
if (areaStart > end) { if (areaStart > end) {
@@ -4251,23 +4194,10 @@ 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; current != NULL;
current = current->cache_next) { current = current->cache_next) {
VMArea* next = current->address_space->NextArea(current); if (!current->address_space->CanResizeArea(current, newSize))
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;
return B_ERROR; 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; for (VMArea* current = cache->areas; current != NULL;
current = current->cache_next) { current = current->cache_next) {
VMArea* next = current->address_space->NextArea(current); status = current->address_space->ResizeArea(current, newSize);
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);
if (status != B_OK) if (status != B_OK)
break; break;
// We also need to unmap all pages beyond the new size, if the area has // We also need to unmap all pages beyond the new size, if the area has
// shrinked // shrunk
if (newSize < oldSize) { if (newSize < oldSize) {
vm_unmap_pages(current, current->Base() + newSize, oldSize - newSize, vm_unmap_pages(current, current->Base() + newSize, oldSize - newSize,
false); 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. // This can fail, too, in which case we're seriously screwed.
for (VMArea* current = cache->areas; current != NULL; for (VMArea* current = cache->areas; current != NULL;
current = current->cache_next) { current = current->cache_next) {
if (current->address_space->ResizeAreaTail(current, oldSize) if (current->address_space->ResizeArea(current, oldSize)
!= B_OK) { != B_OK) {
panic("vm_resize_area(): Failed and not being able to restore " panic("vm_resize_area(): Failed and not being able to restore "
"original state."); "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; return B_BAD_TEAM_ID;
VMArea* area; VMArea* area;
for (VMAddressSpace::Iterator it = locker.AddressSpace()->GetIterator(); for (VMAddressSpace::AreaIterator it
= locker.AddressSpace()->GetAreaIterator();
(area = it.Next()) != NULL;) { (area = it.Next()) != NULL;) {
if (area->id == RESERVED_AREA_ID)
continue;
if (area->Base() > nextBase) if (area->Base() > nextBase)
break; break;
} }