* Copyright 2009-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2002-2009, Axel DΓΆrfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
* Distributed under the terms of the NewOS License.
*/
#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;
}
range of this area.
The area's top cache must be locked.
*/
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;
}
The area's top cache must be locked.
*/
void
VMArea::Wire(VMAreaWiredRange* range)
{
ASSERT(range->area == NULL);
range->area = this;
fWiredRanges.Add(range);
}
Must balance a previous Wire() call.
The area's top cache must be locked.
*/
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();
}
Must balance a previous Wire() call. The first implicit range with matching
\a base, \a size, and \a writable attributes is removed and returned. It's
waiters are woken up as well.
The area's top cache must be locked.
*/
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;
}
prepared for waiting.
\return \c true, if the waiter has been added, \c false otherwise.
*/
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;
}
given waiter is added to the range and prepared for waiting.
\param waiter The waiter structure that will be added to the wired range
that intersects with the given address range.
\param base The base of the address range to check.
\param size The size of the address range to check.
\param flags
- \c IGNORE_WRITE_WIRED_RANGES: Ignore ranges wired for writing.
\return \c true, if the waiter has been added, \c false otherwise.
*/
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();
}