* 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>
#define AREA_HASH_TABLE_SIZE 1024
rw_lock VMAreaHash::sLock = RW_LOCK_INITIALIZER("area hash");
VMAreaHashTable VMAreaHash::sTable;
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),
no_cache_change(0),
cache_offset(0),
cache_type(0),
page_protections(NULL),
address_space(addressSpace),
cache_next(NULL),
cache_prev(NULL),
hash_next(NULL)
{
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::Iterator 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::Iterator 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::Iterator 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
VMAreaHash::Init()
{
return sTable.Init(AREA_HASH_TABLE_SIZE);
}
VMArea*
VMAreaHash::Lookup(area_id id)
{
ReadLock();
VMArea* area = LookupLocked(id);
ReadUnlock();
return area;
}
area_id
VMAreaHash::Find(const char* name)
{
ReadLock();
area_id id = B_NAME_NOT_FOUND;
for (VMAreaHashTable::Iterator it = sTable.GetIterator();
VMArea* area = it.Next();) {
if (strcmp(area->name, name) == 0) {
id = area->id;
break;
}
}
ReadUnlock();
return id;
}
void
VMAreaHash::Insert(VMArea* area)
{
WriteLock();
sTable.InsertUnchecked(area);
WriteUnlock();
}
void
VMAreaHash::Remove(VMArea* area)
{
WriteLock();
sTable.RemoveUnchecked(area);
WriteUnlock();
}