btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / system / kernel / vm / VMAddressSpace.cpp
blob7c58a05e56fd6523c6479abc207724927a59cfe4
1 /*
2 * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de.
4 * Distributed under the terms of the MIT License.
6 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
7 * Distributed under the terms of the NewOS License.
8 */
11 #include <vm/VMAddressSpace.h>
13 #include <stdlib.h>
15 #include <new>
17 #include <KernelExport.h>
19 #include <util/OpenHashTable.h>
21 #include <heap.h>
22 #include <thread.h>
23 #include <vm/vm.h>
24 #include <vm/VMArea.h>
25 #include <vm/VMCache.h>
27 #include "VMKernelAddressSpace.h"
28 #include "VMUserAddressSpace.h"
31 //#define TRACE_VM
32 #ifdef TRACE_VM
33 # define TRACE(x) dprintf x
34 #else
35 # define TRACE(x) ;
36 #endif
39 #define ASPACE_HASH_TABLE_SIZE 1024
42 // #pragma mark - AddressSpaceHashDefinition
45 namespace {
47 struct AddressSpaceHashDefinition {
48 typedef team_id KeyType;
49 typedef VMAddressSpace ValueType;
51 size_t HashKey(team_id key) const
53 return key;
56 size_t Hash(const VMAddressSpace* value) const
58 return HashKey(value->ID());
61 bool Compare(team_id key, const VMAddressSpace* value) const
63 return value->ID() == key;
66 VMAddressSpace*& GetLink(VMAddressSpace* value) const
68 return value->HashTableLink();
72 typedef BOpenHashTable<AddressSpaceHashDefinition> AddressSpaceTable;
74 } // namespace
77 static AddressSpaceTable sAddressSpaceTable;
78 static rw_lock sAddressSpaceTableLock;
80 VMAddressSpace* VMAddressSpace::sKernelAddressSpace;
83 // #pragma mark - VMAddressSpace
86 VMAddressSpace::VMAddressSpace(team_id id, addr_t base, size_t size,
87 const char* name)
89 fBase(base),
90 fEndAddress(base + (size - 1)),
91 fFreeSpace(size),
92 fID(id),
93 fRefCount(1),
94 fFaultCount(0),
95 fChangeCount(0),
96 fTranslationMap(NULL),
97 fRandomizingEnabled(true),
98 fDeleting(false)
100 rw_lock_init(&fLock, name);
101 // rw_lock_init(&fLock, kernel ? "kernel address space" : "address space");
105 VMAddressSpace::~VMAddressSpace()
107 TRACE(("VMAddressSpace::~VMAddressSpace: called on aspace %" B_PRId32 "\n",
108 ID()));
110 WriteLock();
112 delete fTranslationMap;
114 rw_lock_destroy(&fLock);
118 /*static*/ status_t
119 VMAddressSpace::Init()
121 rw_lock_init(&sAddressSpaceTableLock, "address spaces table");
123 // create the area and address space hash tables
125 new(&sAddressSpaceTable) AddressSpaceTable;
126 status_t error = sAddressSpaceTable.Init(ASPACE_HASH_TABLE_SIZE);
127 if (error != B_OK)
128 panic("vm_init: error creating aspace hash table\n");
131 // create the initial kernel address space
132 if (Create(B_SYSTEM_TEAM, KERNEL_BASE, KERNEL_SIZE, true,
133 &sKernelAddressSpace) != B_OK) {
134 panic("vm_init: error creating kernel address space!\n");
137 add_debugger_command("aspaces", &_DumpListCommand,
138 "Dump a list of all address spaces");
139 add_debugger_command("aspace", &_DumpCommand,
140 "Dump info about a particular address space");
142 return B_OK;
146 /*! Deletes all areas in the specified address space, and the address
147 space by decreasing all reference counters. It also marks the
148 address space of being in deletion state, so that no more areas
149 can be created in it.
150 After this, the address space is not operational anymore, but might
151 still be in memory until the last reference has been released.
153 void
154 VMAddressSpace::RemoveAndPut()
156 WriteLock();
157 fDeleting = true;
158 WriteUnlock();
160 vm_delete_areas(this, true);
161 Put();
165 status_t
166 VMAddressSpace::InitObject()
168 return B_OK;
172 void
173 VMAddressSpace::Dump() const
175 kprintf("dump of address space at %p:\n", this);
176 kprintf("id: %" B_PRId32 "\n", fID);
177 kprintf("ref_count: %" B_PRId32 "\n", fRefCount);
178 kprintf("fault_count: %" B_PRId32 "\n", fFaultCount);
179 kprintf("translation_map: %p\n", fTranslationMap);
180 kprintf("base: %#" B_PRIxADDR "\n", fBase);
181 kprintf("end: %#" B_PRIxADDR "\n", fEndAddress);
182 kprintf("change_count: %" B_PRId32 "\n", fChangeCount);
186 /*static*/ status_t
187 VMAddressSpace::Create(team_id teamID, addr_t base, size_t size, bool kernel,
188 VMAddressSpace** _addressSpace)
190 VMAddressSpace* addressSpace = kernel
191 ? (VMAddressSpace*)new(std::nothrow) VMKernelAddressSpace(teamID, base,
192 size)
193 : (VMAddressSpace*)new(std::nothrow) VMUserAddressSpace(teamID, base,
194 size);
195 if (addressSpace == NULL)
196 return B_NO_MEMORY;
198 status_t status = addressSpace->InitObject();
199 if (status != B_OK) {
200 delete addressSpace;
201 return status;
204 TRACE(("VMAddressSpace::Create(): team %" B_PRId32 " (%skernel): %#lx "
205 "bytes starting at %#lx => %p\n", teamID, kernel ? "" : "!", size,
206 base, addressSpace));
208 // create the corresponding translation map
209 status = arch_vm_translation_map_create_map(kernel,
210 &addressSpace->fTranslationMap);
211 if (status != B_OK) {
212 delete addressSpace;
213 return status;
216 // add the aspace to the global hash table
217 rw_lock_write_lock(&sAddressSpaceTableLock);
218 sAddressSpaceTable.InsertUnchecked(addressSpace);
219 rw_lock_write_unlock(&sAddressSpaceTableLock);
221 *_addressSpace = addressSpace;
222 return B_OK;
226 /*static*/ VMAddressSpace*
227 VMAddressSpace::GetKernel()
229 // we can treat this one a little differently since it can't be deleted
230 sKernelAddressSpace->Get();
231 return sKernelAddressSpace;
235 /*static*/ team_id
236 VMAddressSpace::CurrentID()
238 Thread* thread = thread_get_current_thread();
240 if (thread != NULL && thread->team->address_space != NULL)
241 return thread->team->id;
243 return B_ERROR;
247 /*static*/ VMAddressSpace*
248 VMAddressSpace::GetCurrent()
250 Thread* thread = thread_get_current_thread();
252 if (thread != NULL) {
253 VMAddressSpace* addressSpace = thread->team->address_space;
254 if (addressSpace != NULL) {
255 addressSpace->Get();
256 return addressSpace;
260 return NULL;
264 /*static*/ VMAddressSpace*
265 VMAddressSpace::Get(team_id teamID)
267 rw_lock_read_lock(&sAddressSpaceTableLock);
268 VMAddressSpace* addressSpace = sAddressSpaceTable.Lookup(teamID);
269 if (addressSpace)
270 addressSpace->Get();
271 rw_lock_read_unlock(&sAddressSpaceTableLock);
273 return addressSpace;
277 /*static*/ VMAddressSpace*
278 VMAddressSpace::DebugFirst()
280 return sAddressSpaceTable.GetIterator().Next();
284 /*static*/ VMAddressSpace*
285 VMAddressSpace::DebugNext(VMAddressSpace* addressSpace)
287 if (addressSpace == NULL)
288 return NULL;
290 AddressSpaceTable::Iterator it
291 = sAddressSpaceTable.GetIterator(addressSpace->ID());
292 it.Next();
293 return it.Next();
297 /*static*/ VMAddressSpace*
298 VMAddressSpace::DebugGet(team_id teamID)
300 return sAddressSpaceTable.Lookup(teamID);
304 /*static*/ void
305 VMAddressSpace::_DeleteIfUnreferenced(team_id id)
307 rw_lock_write_lock(&sAddressSpaceTableLock);
309 bool remove = false;
310 VMAddressSpace* addressSpace = sAddressSpaceTable.Lookup(id);
311 if (addressSpace != NULL && addressSpace->fRefCount == 0) {
312 sAddressSpaceTable.RemoveUnchecked(addressSpace);
313 remove = true;
316 rw_lock_write_unlock(&sAddressSpaceTableLock);
318 if (remove)
319 delete addressSpace;
323 /*static*/ int
324 VMAddressSpace::_DumpCommand(int argc, char** argv)
326 VMAddressSpace* aspace;
328 if (argc < 2) {
329 kprintf("aspace: not enough arguments\n");
330 return 0;
333 // if the argument looks like a number, treat it as such
336 team_id id = strtoul(argv[1], NULL, 0);
338 aspace = sAddressSpaceTable.Lookup(id);
339 if (aspace == NULL) {
340 kprintf("invalid aspace id\n");
341 } else {
342 aspace->Dump();
344 return 0;
346 return 0;
350 /*static*/ int
351 VMAddressSpace::_DumpListCommand(int argc, char** argv)
353 kprintf(" %*s id %*s %*s area count area size\n",
354 B_PRINTF_POINTER_WIDTH, "address", B_PRINTF_POINTER_WIDTH, "base",
355 B_PRINTF_POINTER_WIDTH, "end");
357 AddressSpaceTable::Iterator it = sAddressSpaceTable.GetIterator();
358 while (VMAddressSpace* space = it.Next()) {
359 int32 areaCount = 0;
360 off_t areaSize = 0;
361 for (VMAddressSpace::AreaIterator areaIt = space->GetAreaIterator();
362 VMArea* area = areaIt.Next();) {
363 areaCount++;
364 areaSize += area->Size();
366 kprintf("%p %6" B_PRId32 " %#010" B_PRIxADDR " %#10" B_PRIxADDR
367 " %10" B_PRId32 " %10" B_PRIdOFF "\n", space, space->ID(),
368 space->Base(), space->EndAddress(), areaCount, areaSize);
371 return 0;