btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / system / kernel / vm / VMArea.cpp
blobffe111e13fc1acdf6b9516201b02c6570472d959
1 /*
2 * Copyright 2009-2010, 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/VMArea.h>
13 #include <new>
15 #include <heap.h>
16 #include <vm/VMAddressSpace.h>
19 #define AREA_HASH_TABLE_SIZE 1024
22 rw_lock VMAreaHash::sLock = RW_LOCK_INITIALIZER("area hash");
23 VMAreaHashTable VMAreaHash::sTable;
24 static area_id sNextAreaID = 1;
27 // #pragma mark - VMArea
29 VMArea::VMArea(VMAddressSpace* addressSpace, uint32 wiring, uint32 protection)
31 name(NULL),
32 protection(protection),
33 wiring(wiring),
34 memory_type(0),
35 cache(NULL),
36 no_cache_change(0),
37 cache_offset(0),
38 cache_type(0),
39 page_protections(NULL),
40 address_space(addressSpace),
41 cache_next(NULL),
42 cache_prev(NULL),
43 hash_next(NULL)
45 new (&mappings) VMAreaMappings;
49 VMArea::~VMArea()
51 const uint32 flags = HEAP_DONT_WAIT_FOR_MEMORY
52 | HEAP_DONT_LOCK_KERNEL_SPACE;
53 // TODO: This might be stricter than necessary.
55 free_etc(page_protections, flags);
56 free_etc(name, flags);
60 status_t
61 VMArea::Init(const char* name, uint32 allocationFlags)
63 // restrict the area name to B_OS_NAME_LENGTH
64 size_t length = strlen(name) + 1;
65 if (length > B_OS_NAME_LENGTH)
66 length = B_OS_NAME_LENGTH;
68 // clone the name
69 this->name = (char*)malloc_etc(length, allocationFlags);
70 if (this->name == NULL)
71 return B_NO_MEMORY;
72 strlcpy(this->name, name, length);
74 id = atomic_add(&sNextAreaID, 1);
75 return B_OK;
79 /*! Returns whether any part of the given address range intersects with a wired
80 range of this area.
81 The area's top cache must be locked.
83 bool
84 VMArea::IsWired(addr_t base, size_t size) const
86 for (VMAreaWiredRangeList::Iterator it = fWiredRanges.GetIterator();
87 VMAreaWiredRange* range = it.Next();) {
88 if (range->IntersectsWith(base, size))
89 return true;
92 return false;
96 /*! Adds the given wired range to this area.
97 The area's top cache must be locked.
99 void
100 VMArea::Wire(VMAreaWiredRange* range)
102 ASSERT(range->area == NULL);
104 range->area = this;
105 fWiredRanges.Add(range);
109 /*! Removes the given wired range from this area.
110 Must balance a previous Wire() call.
111 The area's top cache must be locked.
113 void
114 VMArea::Unwire(VMAreaWiredRange* range)
116 ASSERT(range->area == this);
118 // remove the range
119 range->area = NULL;
120 fWiredRanges.Remove(range);
122 // wake up waiters
123 for (VMAreaUnwiredWaiterList::Iterator it = range->waiters.GetIterator();
124 VMAreaUnwiredWaiter* waiter = it.Next();) {
125 waiter->condition.NotifyAll();
128 range->waiters.MakeEmpty();
132 /*! Removes a wired range from this area.
134 Must balance a previous Wire() call. The first implicit range with matching
135 \a base, \a size, and \a writable attributes is removed and returned. It's
136 waiters are woken up as well.
137 The area's top cache must be locked.
139 VMAreaWiredRange*
140 VMArea::Unwire(addr_t base, size_t size, bool writable)
142 for (VMAreaWiredRangeList::Iterator it = fWiredRanges.GetIterator();
143 VMAreaWiredRange* range = it.Next();) {
144 if (range->implicit && range->base == base && range->size == size
145 && range->writable == writable) {
146 Unwire(range);
147 return range;
151 panic("VMArea::Unwire(%#" B_PRIxADDR ", %#" B_PRIxADDR ", %d): no such "
152 "range", base, size, writable);
153 return NULL;
157 /*! If the area has any wired range, the given waiter is added to the range and
158 prepared for waiting.
160 \return \c true, if the waiter has been added, \c false otherwise.
162 bool
163 VMArea::AddWaiterIfWired(VMAreaUnwiredWaiter* waiter)
165 VMAreaWiredRange* range = fWiredRanges.Head();
166 if (range == NULL)
167 return false;
169 waiter->area = this;
170 waiter->base = fBase;
171 waiter->size = fSize;
172 waiter->condition.Init(this, "area unwired");
173 waiter->condition.Add(&waiter->waitEntry);
175 range->waiters.Add(waiter);
177 return true;
181 /*! If the given address range intersect with a wired range of this area, the
182 given waiter is added to the range and prepared for waiting.
184 \param waiter The waiter structure that will be added to the wired range
185 that intersects with the given address range.
186 \param base The base of the address range to check.
187 \param size The size of the address range to check.
188 \param flags
189 - \c IGNORE_WRITE_WIRED_RANGES: Ignore ranges wired for writing.
190 \return \c true, if the waiter has been added, \c false otherwise.
192 bool
193 VMArea::AddWaiterIfWired(VMAreaUnwiredWaiter* waiter, addr_t base, size_t size,
194 uint32 flags)
196 for (VMAreaWiredRangeList::Iterator it = fWiredRanges.GetIterator();
197 VMAreaWiredRange* range = it.Next();) {
198 if ((flags & IGNORE_WRITE_WIRED_RANGES) != 0 && range->writable)
199 continue;
201 if (range->IntersectsWith(base, size)) {
202 waiter->area = this;
203 waiter->base = base;
204 waiter->size = size;
205 waiter->condition.Init(this, "area unwired");
206 waiter->condition.Add(&waiter->waitEntry);
208 range->waiters.Add(waiter);
210 return true;
214 return false;
218 // #pragma mark - VMAreaHash
221 /*static*/ status_t
222 VMAreaHash::Init()
224 return sTable.Init(AREA_HASH_TABLE_SIZE);
228 /*static*/ VMArea*
229 VMAreaHash::Lookup(area_id id)
231 ReadLock();
232 VMArea* area = LookupLocked(id);
233 ReadUnlock();
234 return area;
238 /*static*/ area_id
239 VMAreaHash::Find(const char* name)
241 ReadLock();
243 area_id id = B_NAME_NOT_FOUND;
245 // TODO: Iterating through the whole table can be very slow and the whole
246 // time we're holding the lock! Use a second hash table!
248 for (VMAreaHashTable::Iterator it = sTable.GetIterator();
249 VMArea* area = it.Next();) {
250 if (strcmp(area->name, name) == 0) {
251 id = area->id;
252 break;
256 ReadUnlock();
258 return id;
262 /*static*/ void
263 VMAreaHash::Insert(VMArea* area)
265 WriteLock();
266 sTable.InsertUnchecked(area);
267 WriteUnlock();
271 /*static*/ void
272 VMAreaHash::Remove(VMArea* area)
274 WriteLock();
275 sTable.RemoveUnchecked(area);
276 WriteUnlock();