#include <vm/VMArea.h>
#include <new>
#include <heap.h>
#include <vm/VMAddressSpace.h>
rw_lock VMAreas::sLock = RW_LOCK_INITIALIZER("areas tree");
VMAreasTree VMAreas::sTree;
static area_id sNextAreaID = 1;
VMArea::VMArea(VMAddressSpace* addressSpace, uint32 wiring, uint32 protection)
:
protection(protection),
protection_max(0),
wiring(wiring),
memory_type(0),
cache(NULL),
cache_offset(0),
cache_type(0),
page_protections(NULL),
address_space(addressSpace)
{
new (&mappings) VMAreaMappings;
}
VMArea::~VMArea()
{
free_etc(page_protections, address_space == VMAddressSpace::Kernel()
? HEAP_DONT_WAIT_FOR_MEMORY | HEAP_DONT_LOCK_KERNEL_SPACE : 0);
}
status_t
VMArea::Init(const char* name, uint32 allocationFlags)
{
strlcpy(this->name, name, B_OS_NAME_LENGTH);
id = atomic_add(&sNextAreaID, 1);
return B_OK;
}
bool
VMArea::IsWired(addr_t base, size_t size) const
{
for (VMAreaWiredRangeList::ConstIterator it = fWiredRanges.GetIterator();
VMAreaWiredRange* range = it.Next();) {
if (range->IntersectsWith(base, size))
return true;
}
return false;
}
void
VMArea::Wire(VMAreaWiredRange* range)
{
ASSERT(range->area == NULL);
range->area = this;
fWiredRanges.Add(range);
}
void
VMArea::Unwire(VMAreaWiredRange* range)
{
ASSERT(range->area == this);
range->area = NULL;
fWiredRanges.Remove(range);
for (VMAreaUnwiredWaiterList::Iterator it = range->waiters.GetIterator();
VMAreaUnwiredWaiter* waiter = it.Next();) {
waiter->condition.NotifyAll();
}
range->waiters.MakeEmpty();
}
VMAreaWiredRange*
VMArea::Unwire(addr_t base, size_t size, bool writable)
{
for (VMAreaWiredRangeList::ConstIterator it = fWiredRanges.GetIterator();
VMAreaWiredRange* range = it.Next();) {
if (range->implicit && range->base == base && range->size == size
&& range->writable == writable) {
Unwire(range);
return range;
}
}
panic("VMArea::Unwire(%#" B_PRIxADDR ", %#" B_PRIxADDR ", %d): no such "
"range", base, size, writable);
return NULL;
}
bool
VMArea::AddWaiterIfWired(VMAreaUnwiredWaiter* waiter)
{
VMAreaWiredRange* range = fWiredRanges.Head();
if (range == NULL)
return false;
waiter->area = this;
waiter->base = fBase;
waiter->size = fSize;
waiter->condition.Init(this, "area unwired");
waiter->condition.Add(&waiter->waitEntry);
range->waiters.Add(waiter);
return true;
}
bool
VMArea::AddWaiterIfWired(VMAreaUnwiredWaiter* waiter, addr_t base, size_t size,
uint32 flags)
{
for (VMAreaWiredRangeList::ConstIterator it = fWiredRanges.GetIterator();
VMAreaWiredRange* range = it.Next();) {
if ((flags & IGNORE_WRITE_WIRED_RANGES) != 0 && range->writable)
continue;
if (range->IntersectsWith(base, size)) {
waiter->area = this;
waiter->base = base;
waiter->size = size;
waiter->condition.Init(this, "area unwired");
waiter->condition.Add(&waiter->waitEntry);
range->waiters.Add(waiter);
return true;
}
}
return false;
}
status_t
VMAreas::Init()
{
new(&sTree) VMAreasTree;
return B_OK;
}
VMArea*
VMAreas::Lookup(area_id id)
{
ReadLock();
VMArea* area = LookupLocked(id);
ReadUnlock();
return area;
}
area_id
VMAreas::Find(const char* name)
{
ReadLock();
area_id id = B_NAME_NOT_FOUND;
for (VMAreasTree::Iterator it = sTree.GetIterator();
VMArea* area = it.Next();) {
if (strcmp(area->name, name) == 0) {
id = area->id;
break;
}
}
ReadUnlock();
return id;
}
status_t
VMAreas::Insert(VMArea* area)
{
WriteLock();
status_t status = sTree.Insert(area);
WriteUnlock();
return status;
}
void
VMAreas::Remove(VMArea* area)
{
WriteLock();
sTree.Remove(area);
WriteUnlock();
}