* Added VMAddressSpace::ResizeArea{Head,Tail}() to adjust an area's base

and size.
* Made VMArea::Set{Base,Size}() private and made VMAddressSpace a friend.
  In vm.cpp the new VMAddressSpace::ResizeArea{Head,Tail}() are used
  instead.
Finally all address space changes happen in VMAddressSpace only. *phew*
Now it's ready to be thoroughly butchered. :-)


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34467 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2009-12-03 15:21:18 +00:00
parent 751ce9e228
commit f69032f22b
4 changed files with 74 additions and 23 deletions
@@ -66,6 +66,8 @@ public:
status_t InsertArea(void** _address, uint32 addressSpec,
addr_t size, VMArea* area);
void RemoveArea(VMArea* area);
status_t ResizeAreaHead(VMArea* area, size_t size);
status_t ResizeAreaTail(VMArea* area, size_t size);
inline Iterator GetIterator();
+7 -3
View File
@@ -42,9 +42,6 @@ struct VMArea {
addr_t Base() const { return fBase; }
size_t Size() const { return fSize; }
void SetBase(addr_t base) { fBase = base; }
void SetSize(size_t size) { fSize = size; }
bool ContainsAddress(addr_t address) const
{ return address >= fBase
&& address <= fBase + (fSize - 1); }
@@ -60,6 +57,13 @@ struct VMArea {
const DoublyLinkedListLink<VMArea>& AddressSpaceLink() const
{ return fAddressSpaceLink; }
private:
friend class VMAddressSpace;
private:
void SetBase(addr_t base) { fBase = base; }
void SetSize(size_t size) { fSize = size; }
private:
DoublyLinkedListLink<VMArea> fAddressSpaceLink;
addr_t fBase;
+27
View File
@@ -361,6 +361,33 @@ VMAddressSpace::RemoveArea(VMArea* area)
}
status_t
VMAddressSpace::ResizeAreaHead(VMArea* area, size_t size)
{
size_t oldSize = area->Size();
if (size == oldSize)
return B_OK;
area->SetBase(area->Base() + oldSize - size);
area->SetSize(size);
return B_OK;
}
status_t
VMAddressSpace::ResizeAreaTail(VMArea* area, size_t size)
{
size_t oldSize = area->Size();
if (size == oldSize)
return B_OK;
area->SetSize(size);
return B_OK;
}
void
VMAddressSpace::Dump() const
{
+38 -20
View File
@@ -335,37 +335,46 @@ cut_area(VMAddressSpace* addressSpace, VMArea* area, addr_t address,
// Cut the end only?
if (areaLast <= lastAddress) {
addr_t newSize = address - area->Base();
size_t oldSize = area->Size();
size_t newSize = address - area->Base();
status_t error = addressSpace->ResizeAreaTail(area, newSize);
if (error != B_OK)
return error;
// unmap pages
vm_unmap_pages(area, address, area->Size() - newSize, false);
vm_unmap_pages(area, address, oldSize - newSize, false);
// If no one else uses the area's cache, we can resize it, too.
if (cache->areas == area && area->cache_next == NULL
&& list_is_empty(&cache->consumers)) {
status_t error = cache->Resize(cache->virtual_base + newSize);
if (error != B_OK)
error = cache->Resize(cache->virtual_base + newSize);
if (error != B_OK) {
addressSpace->ResizeAreaTail(area, oldSize);
return error;
}
}
area->SetSize(newSize);
return B_OK;
}
// Cut the beginning only?
if (area->Base() >= address) {
addr_t oldBase = area->Base();
addr_t newBase = lastAddress + 1;
addr_t newSize = areaLast - lastAddress;
size_t newSize = areaLast - lastAddress;
// unmap pages
vm_unmap_pages(area, area->Base(), newBase - area->Base(), false);
vm_unmap_pages(area, oldBase, newBase - oldBase, false);
// resize the area
status_t error = addressSpace->ResizeAreaHead(area, newSize);
if (error != B_OK)
return error;
// TODO: If no one else uses the area's cache, we should resize it, too!
area->cache_offset += newBase - area->Base();
area->SetBase(newBase);
area->SetSize(newSize);
area->cache_offset += newBase - oldBase;
return B_OK;
}
@@ -383,7 +392,9 @@ cut_area(VMAddressSpace* addressSpace, VMArea* area, addr_t address,
// resize the area
addr_t oldSize = area->Size();
area->SetSize(firstNewSize);
status_t error = addressSpace->ResizeAreaTail(area, firstNewSize);
if (error != B_OK)
return error;
// TODO: If no one else uses the area's cache, we might want to create a
// new cache for the second area, transfer the concerned pages from the
@@ -392,12 +403,12 @@ cut_area(VMAddressSpace* addressSpace, VMArea* area, addr_t address,
// map the second area
VMArea* secondArea;
void* secondBaseAddress = (void*)secondBase;
status_t error = map_backing_store(addressSpace, cache, &secondBaseAddress,
error = map_backing_store(addressSpace, cache, &secondBaseAddress,
area->cache_offset + (secondBase - area->Base()), secondSize,
B_EXACT_ADDRESS, area->wiring, area->protection, REGION_NO_PRIVATE_MAP,
&secondArea, area->name, false, kernel);
if (error != B_OK) {
area->SetSize(oldSize);
addressSpace->ResizeAreaTail(area, oldSize);
return error;
}
@@ -4283,8 +4294,8 @@ vm_resize_area(area_id areaID, size_t newSize, bool kernel)
next->address_space->RemoveArea(next);
free(next);
} else {
next->SetSize(next->Size() - offset);
next->SetBase(next->Base() + offset);
next->address_space->ResizeAreaHead(next,
next->Size() - offset);
}
} else {
panic("resize situation for area %p has changed although we "
@@ -4294,7 +4305,9 @@ vm_resize_area(area_id areaID, size_t newSize, bool kernel)
}
}
current->SetSize(newSize);
status = current->address_space->ResizeAreaTail(current, newSize);
if (status != B_OK)
break;
// We also need to unmap all pages beyond the new size, if the area has
// shrinked
@@ -4308,11 +4321,16 @@ vm_resize_area(area_id areaID, size_t newSize, bool kernel)
if (status == B_OK && newSize < oldSize)
status = cache->Resize(cache->virtual_base + newSize);
if (status < B_OK) {
// This shouldn't really be possible, but hey, who knows
if (status != B_OK) {
// Something failed -- resize the areas back to their original size.
// This can fail, too, in which case we're seriously screwed.
for (VMArea* current = cache->areas; current != NULL;
current = current->cache_next) {
current->SetSize(oldSize);
if (current->address_space->ResizeAreaTail(current, oldSize)
!= B_OK) {
panic("vm_resize_area(): Failed and not being able to restore "
"original state.");
}
}
cache->Resize(cache->virtual_base + oldSize);