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.
11 #include <vm/VMArea.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
)
32 protection(protection
),
39 page_protections(NULL
),
40 address_space(addressSpace
),
45 new (&mappings
) VMAreaMappings
;
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
);
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
;
69 this->name
= (char*)malloc_etc(length
, allocationFlags
);
70 if (this->name
== NULL
)
72 strlcpy(this->name
, name
, length
);
74 id
= atomic_add(&sNextAreaID
, 1);
79 /*! Returns whether any part of the given address range intersects with a wired
81 The area's top cache must be locked.
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
))
96 /*! Adds the given wired range to this area.
97 The area's top cache must be locked.
100 VMArea::Wire(VMAreaWiredRange
* range
)
102 ASSERT(range
->area
== NULL
);
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.
114 VMArea::Unwire(VMAreaWiredRange
* range
)
116 ASSERT(range
->area
== this);
120 fWiredRanges
.Remove(range
);
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.
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
) {
151 panic("VMArea::Unwire(%#" B_PRIxADDR
", %#" B_PRIxADDR
", %d): no such "
152 "range", base
, size
, writable
);
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.
163 VMArea::AddWaiterIfWired(VMAreaUnwiredWaiter
* waiter
)
165 VMAreaWiredRange
* range
= fWiredRanges
.Head();
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
);
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.
189 - \c IGNORE_WRITE_WIRED_RANGES: Ignore ranges wired for writing.
190 \return \c true, if the waiter has been added, \c false otherwise.
193 VMArea::AddWaiterIfWired(VMAreaUnwiredWaiter
* waiter
, addr_t base
, size_t size
,
196 for (VMAreaWiredRangeList::Iterator it
= fWiredRanges
.GetIterator();
197 VMAreaWiredRange
* range
= it
.Next();) {
198 if ((flags
& IGNORE_WRITE_WIRED_RANGES
) != 0 && range
->writable
)
201 if (range
->IntersectsWith(base
, size
)) {
205 waiter
->condition
.Init(this, "area unwired");
206 waiter
->condition
.Add(&waiter
->waitEntry
);
208 range
->waiters
.Add(waiter
);
218 // #pragma mark - VMAreaHash
224 return sTable
.Init(AREA_HASH_TABLE_SIZE
);
229 VMAreaHash::Lookup(area_id id
)
232 VMArea
* area
= LookupLocked(id
);
239 VMAreaHash::Find(const char* name
)
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) {
263 VMAreaHash::Insert(VMArea
* area
)
266 sTable
.InsertUnchecked(area
);
272 VMAreaHash::Remove(VMArea
* area
)
275 sTable
.RemoveUnchecked(area
);