/*
* Copyright 2009-2011, 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/VMAddressSpace.h>
#include <stdlib.h>
#include <new>
#include <KernelExport.h>
#include <util/OpenHashTable.h>
#include <heap.h>
#include <thread.h>
#include <vm/vm.h>
#include <vm/VMArea.h>
#include <vm/VMCache.h>
#include "VMKernelAddressSpace.h"
#include "VMUserAddressSpace.h"
//#define TRACE_VM
#ifdef TRACE_VM
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
#define ASPACE_HASH_TABLE_SIZE 1024
// #pragma mark - AddressSpaceHashDefinition
namespace {
struct AddressSpaceHashDefinition {
typedef team_id KeyType;
typedef VMAddressSpace ValueType;
size_t HashKey(team_id key) const
{
return key;
}
size_t Hash(const VMAddressSpace* value) const
{
return HashKey(value->ID());
}
bool Compare(team_id key, const VMAddressSpace* value) const
{
return value->ID() == key;
}
VMAddressSpace*& GetLink(VMAddressSpace* value) const
{
return value->HashTableLink();
}
};
typedef BOpenHashTable<AddressSpaceHashDefinition> AddressSpaceTable;
} // namespace
static AddressSpaceTable sAddressSpaceTable;
static rw_lock sAddressSpaceTableLock;
VMAddressSpace* VMAddressSpace::sKernelAddressSpace;
// #pragma mark - VMAddressSpace
VMAddressSpace::VMAddressSpace(team_id id, addr_t base, size_t size,
const char* name)
:
fBase(base),
fEndAddress(base + (size - 1)),
fFreeSpace(size),
fID(id),
fRefCount(1),
fFaultCount(0),
fChangeCount(0),
fTranslationMap(NULL),
fRandomizingEnabled(true),
fDeleting(false)
{
rw_lock_init(&fLock, name);
// rw_lock_init(&fLock, kernel ? "kernel address space" : "address space");
}
VMAddressSpace::~VMAddressSpace()
{
TRACE(("VMAddressSpace::~VMAddressSpace: called on aspace %" B_PRId32 "\n",
ID()));
WriteLock();
delete fTranslationMap;
rw_lock_destroy(&fLock);
}
/*static*/ status_t
VMAddressSpace::Init()
{
rw_lock_init(&sAddressSpaceTableLock, "address spaces table");
// create the area and address space hash tables
{
new(&sAddressSpaceTable) AddressSpaceTable;
status_t error = sAddressSpaceTable.Init(ASPACE_HASH_TABLE_SIZE);
if (error != B_OK)
panic("vm_init: error creating aspace hash table\n");
}
// create the initial kernel address space
if (Create(B_SYSTEM_TEAM, KERNEL_BASE, KERNEL_SIZE, true,
&sKernelAddressSpace) != B_OK) {
panic("vm_init: error creating kernel address space!\n");
}
add_debugger_command("aspaces", &_DumpListCommand,
"Dump a list of all address spaces");
add_debugger_command("aspace", &_DumpCommand,
"Dump info about a particular address space");
return B_OK;
}
/*! Deletes all areas in the specified address space, and the address
space by decreasing all reference counters. It also marks the
address space of being in deletion state, so that no more areas
can be created in it.
After this, the address space is not operational anymore, but might
still be in memory until the last reference has been released.
*/
void
VMAddressSpace::RemoveAndPut()
{
WriteLock();
fDeleting = true;
WriteUnlock();
vm_delete_areas(this, true);
Put();
}
status_t
VMAddressSpace::InitObject()
{
return B_OK;
}
void
VMAddressSpace::Dump() const
{
kprintf("dump of address space at %p:\n", this);
kprintf("id: %" B_PRId32 "\n", fID);
kprintf("ref_count: %" B_PRId32 "\n", fRefCount);
kprintf("fault_count: %" B_PRId32 "\n", fFaultCount);
kprintf("translation_map: %p\n", fTranslationMap);
kprintf("base: %#" B_PRIxADDR "\n", fBase);
kprintf("end: %#" B_PRIxADDR "\n", fEndAddress);
kprintf("change_count: %" B_PRId32 "\n", fChangeCount);
}
/*static*/ status_t
VMAddressSpace::Create(team_id teamID, addr_t base, size_t size, bool kernel,
VMAddressSpace** _addressSpace)
{
VMAddressSpace* addressSpace = kernel
? (VMAddressSpace*)new(std::nothrow) VMKernelAddressSpace(teamID, base,
size)
: (VMAddressSpace*)new(std::nothrow) VMUserAddressSpace(teamID, base,
size);
if (addressSpace == NULL)
return B_NO_MEMORY;
status_t status = addressSpace->InitObject();
if (status != B_OK) {
delete addressSpace;
return status;
}
TRACE(("VMAddressSpace::Create(): team %" B_PRId32 " (%skernel): %#lx "
"bytes starting at %#lx => %p\n", teamID, kernel ? "" : "!", size,
base, addressSpace));
// create the corresponding translation map
status = arch_vm_translation_map_create_map(kernel,
&addressSpace->fTranslationMap);
if (status != B_OK) {
delete addressSpace;
return status;
}
// add the aspace to the global hash table
rw_lock_write_lock(&sAddressSpaceTableLock);
sAddressSpaceTable.InsertUnchecked(addressSpace);
rw_lock_write_unlock(&sAddressSpaceTableLock);
*_addressSpace = addressSpace;
return B_OK;
}
/*static*/ VMAddressSpace*
VMAddressSpace::GetKernel()
{
// we can treat this one a little differently since it can't be deleted
sKernelAddressSpace->Get();
return sKernelAddressSpace;
}
/*static*/ team_id
VMAddressSpace::CurrentID()
{
Thread* thread = thread_get_current_thread();
if (thread != NULL && thread->team->address_space != NULL)
return thread->team->id;
return B_ERROR;
}
/*static*/ VMAddressSpace*
VMAddressSpace::GetCurrent()
{
Thread* thread = thread_get_current_thread();
if (thread != NULL) {
VMAddressSpace* addressSpace = thread->team->address_space;
if (addressSpace != NULL) {
addressSpace->Get();
return addressSpace;
}
}
return NULL;
}
/*static*/ VMAddressSpace*
VMAddressSpace::Get(team_id teamID)
{
rw_lock_read_lock(&sAddressSpaceTableLock);
VMAddressSpace* addressSpace = sAddressSpaceTable.Lookup(teamID);
if (addressSpace)
addressSpace->Get();
rw_lock_read_unlock(&sAddressSpaceTableLock);
return addressSpace;
}
/*static*/ VMAddressSpace*
VMAddressSpace::DebugFirst()
{
return sAddressSpaceTable.GetIterator().Next();
}
/*static*/ VMAddressSpace*
VMAddressSpace::DebugNext(VMAddressSpace* addressSpace)
{
if (addressSpace == NULL)
return NULL;
AddressSpaceTable::Iterator it
= sAddressSpaceTable.GetIterator(addressSpace->ID());
it.Next();
return it.Next();
}
/*static*/ VMAddressSpace*
VMAddressSpace::DebugGet(team_id teamID)
{
return sAddressSpaceTable.Lookup(teamID);
}
/*static*/ void
VMAddressSpace::_DeleteIfUnreferenced(team_id id)
{
rw_lock_write_lock(&sAddressSpaceTableLock);
bool remove = false;
VMAddressSpace* addressSpace = sAddressSpaceTable.Lookup(id);
if (addressSpace != NULL && addressSpace->fRefCount == 0) {
sAddressSpaceTable.RemoveUnchecked(addressSpace);
remove = true;
}
rw_lock_write_unlock(&sAddressSpaceTableLock);
if (remove)
delete addressSpace;
}
/*static*/ int
VMAddressSpace::_DumpCommand(int argc, char** argv)
{
VMAddressSpace* aspace;
if (argc < 2) {
kprintf("aspace: not enough arguments\n");
return 0;
}
// if the argument looks like a number, treat it as such
{
team_id id = strtoul(argv[1], NULL, 0);
aspace = sAddressSpaceTable.Lookup(id);
if (aspace == NULL) {
kprintf("invalid aspace id\n");
} else {
aspace->Dump();
}
}
return 0;
}
/*static*/ int
VMAddressSpace::_DumpListCommand(int argc, char** argv)
{
kprintf(" %*s id %*s %*s area count area size\n",
B_PRINTF_POINTER_WIDTH, "address", B_PRINTF_POINTER_WIDTH, "base",
B_PRINTF_POINTER_WIDTH, "end");
AddressSpaceTable::Iterator it = sAddressSpaceTable.GetIterator();
while (VMAddressSpace* space = it.Next()) {
int32 areaCount = 0;
off_t areaSize = 0;
for (VMAddressSpace::AreaIterator areaIt = space->GetAreaIterator();
VMArea* area = areaIt.Next();) {
areaCount++;
areaSize += area->Size();
}
kprintf("%p %6" B_PRId32 " %#010" B_PRIxADDR " %#10" B_PRIxADDR
" %10" B_PRId32 " %10" B_PRIdOFF "\n", space, space->ID(),
space->Base(), space->EndAddress(), areaCount, areaSize);
}
return 0;
}
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fHashTableLink.