]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IORangeAllocator.cpp
xnu-344.21.73.tar.gz
[apple/xnu.git] / iokit / Kernel / IORangeAllocator.cpp
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
d7e50217 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
d7e50217
A
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
d7e50217
A
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
1c79356b
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/*
26 * Copyright (c) 1999 Apple Computer, Inc.
27 *
28 *
29 * HISTORY
30 *
31 * sdouglas 05 Nov 99 - created.
32 */
33
34#include <libkern/c++/OSArray.h>
35#include <libkern/c++/OSNumber.h>
36#include <IOKit/IORangeAllocator.h>
37#include <IOKit/IOLib.h>
38#include <IOKit/IOLocks.h>
39#include <IOKit/assert.h>
40
41/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
42
43#undef super
44#define super OSObject
45
46OSDefineMetaClassAndStructors( IORangeAllocator, OSObject )
47
48struct IORangeAllocatorElement {
49 // closed range
50 IORangeScalar start;
51 IORangeScalar end;
52};
53
54IOLock * gIORangeAllocatorLock;
55
56#define LOCK() \
57 if( options & kLocking) IOTakeLock( gIORangeAllocatorLock )
58#define UNLOCK() \
59 if( options & kLocking) IOUnlock( gIORangeAllocatorLock )
60
61/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
62
63bool IORangeAllocator::init( IORangeScalar endOfRange,
64 IORangeScalar _defaultAlignment,
65 UInt32 _capacity,
66 IOOptionBits _options )
67{
68 if( !super::init())
69 return( false );
70
71 if( !_capacity)
72 _capacity = 1;
73 if( !_defaultAlignment)
74 _defaultAlignment = 1;
75 capacity = 0;
76 capacityIncrement = _capacity;
77 numElements = 0;
78 elements = 0;
79 defaultAlignmentMask = _defaultAlignment - 1;
80 options = _options;
81
82 if( (!gIORangeAllocatorLock) && (options & kLocking))
83 gIORangeAllocatorLock = IOLockAlloc();
84
85 if( endOfRange)
86 deallocate( 0, endOfRange + 1 );
87
88 return( true );
89}
90
91IORangeAllocator * IORangeAllocator:: withRange(
92 IORangeScalar endOfRange,
93 IORangeScalar defaultAlignment = 0,
94 UInt32 capacity = 0,
95 IOOptionBits options = 0 )
96{
97 IORangeAllocator * thingy;
98
99 thingy = new IORangeAllocator;
100 if( thingy && ! thingy->init( endOfRange, defaultAlignment,
101 capacity, options )) {
102 thingy->release();
103 thingy = 0;
104 }
105
106 return( thingy );
107}
108
109void IORangeAllocator::free()
110{
111 if( elements)
112 IODelete( elements, IORangeAllocatorElement, capacity );
113
114 super::free();
115}
116
117UInt32 IORangeAllocator::getFragmentCount( void )
118{
119 return( numElements );
120}
121
122UInt32 IORangeAllocator::getFragmentCapacity( void )
123{
124 return( capacity );
125}
126
127void IORangeAllocator::setFragmentCapacityIncrement( UInt32 count )
128{
129 capacityIncrement = count;
130}
131
132
133// allocate element at index
134bool IORangeAllocator::allocElement( UInt32 index )
135{
136 UInt32 newCapacity;
137 IORangeAllocatorElement * newElements;
138
139 if( ((numElements == capacity) && capacityIncrement)
140 || (!elements)) {
141
142 newCapacity = capacity + capacityIncrement;
143 newElements = IONew( IORangeAllocatorElement, newCapacity );
144 if( !newElements)
145 return( false );
146
147 if( elements) {
148 bcopy( elements,
149 newElements,
150 index * sizeof( IORangeAllocatorElement));
151 bcopy( elements + index,
152 newElements + index + 1,
153 (numElements - index) * sizeof( IORangeAllocatorElement));
154
155 IODelete( elements, IORangeAllocatorElement, capacity );
156 }
157
158 elements = newElements;
159 capacity = newCapacity;
160
161 } else {
162
163 bcopy( elements + index,
164 elements + index + 1,
165 (numElements - index) * sizeof( IORangeAllocatorElement));
166 }
167 numElements++;
168
169 return( true );
170}
171
172// destroy element at index
173void IORangeAllocator::deallocElement( UInt32 index )
174{
175 numElements--;
176 bcopy( elements + index + 1,
177 elements + index,
178 (numElements - index) * sizeof( IORangeAllocatorElement));
179}
180
181bool IORangeAllocator::allocate( IORangeScalar size,
182 IORangeScalar * result,
183 IORangeScalar alignment = 0 )
184{
185 IORangeScalar data, dataEnd;
186 IORangeScalar thisStart, thisEnd;
187 UInt32 index;
188 bool ok = false;
189
190 if( !size || !result)
191 return( false );
192
193 if( 0 == alignment)
194 alignment = defaultAlignmentMask;
195 else
196 alignment--;
197
198 size = (size + defaultAlignmentMask) & ~defaultAlignmentMask;
199
200 LOCK();
201
202 for( index = 0; index < numElements; index++ ) {
203
204 thisStart = elements[index].start;
205 thisEnd = elements[index].end;
206 data = (thisStart + alignment) & ~alignment;
207 dataEnd = (data + size - 1);
208
209 ok = (dataEnd <= thisEnd);
210 if( ok) {
211 if( data != thisStart) {
212 if( dataEnd != thisEnd) {
213 if( allocElement( index + 1 )) {
214 elements[index++].end = data - 1;
215 elements[index].start = dataEnd + 1;
216 elements[index].end = thisEnd;
217 } else
218 ok = false;
219 } else
220 elements[index].end = data - 1;
221 } else {
222 if( dataEnd != thisEnd)
223 elements[index].start = dataEnd + 1;
224 else
225 deallocElement( index );
226 }
227 if( ok)
228 *result = data;
229 break;
230 }
231 }
232
233 UNLOCK();
234
235 return( ok );
236}
237
238bool IORangeAllocator::allocateRange( IORangeScalar data,
239 IORangeScalar size )
240{
241 IORangeScalar thisStart, thisEnd;
242 IORangeScalar dataEnd;
243 UInt32 index;
244 bool found = false;
245
246 if( !size)
247 return( 0 );
248
249 size = (size + defaultAlignmentMask) & ~defaultAlignmentMask;
250 dataEnd = data + size - 1;
251
252 LOCK();
253
254 for( index = 0;
255 (!found) && (index < numElements);
256 index++ ) {
257
258 thisStart = elements[index].start;
259 thisEnd = elements[index].end;
260
261 if( thisStart > data)
262 break;
263 found = (dataEnd <= thisEnd);
264
265 if( found) {
266 if( data != thisStart) {
267 if( dataEnd != thisEnd) {
268 found = allocElement( index + 1 );
269 if( found) {
270 elements[index++].end = data - 1;
271 elements[index].start = dataEnd + 1;
272 elements[index].end = thisEnd;
273 }
274 } else
275 elements[index].end = data - 1;
276 } else if( dataEnd != thisEnd)
277 elements[index].start = dataEnd + 1;
278 else
279 deallocElement( index );
280 }
281 }
282
283 UNLOCK();
284
285 return( found );
286}
287
288void IORangeAllocator::deallocate( IORangeScalar data,
289 IORangeScalar size )
290{
291 IORangeScalar dataEnd;
292 UInt32 index;
293 bool headContig = false;
294 bool tailContig = false;
295
296 size = (size + defaultAlignmentMask) & ~defaultAlignmentMask;
297 dataEnd = data + size - 1;
298
299 LOCK();
300
301 for( index = 0; index < numElements; index++ ) {
302 if( elements[index].start < data) {
303 headContig = (data <= (elements[index].end + 1));
304 continue;
305 }
306 tailContig = ((data + size) >= elements[index].start);
307 break;
308 }
309
310 if( headContig) {
311 if( tailContig) {
312 elements[index-1].end = elements[index].end;
313 deallocElement( index );
314 } else /*safe*/ if( dataEnd > elements[index-1].end)
315 elements[index-1].end = dataEnd;
316
317 } else if( tailContig) {
318 if( data < elements[index].start) /*safe*/
319 elements[index].start = data;
320
321 } else if( allocElement( index)) {
322 elements[index].start = data;
323 elements[index].end = dataEnd;
324 }
325
326 UNLOCK();
327}
328
329bool IORangeAllocator::serialize(OSSerialize *s) const
330{
331 OSArray * array = OSArray::withCapacity( numElements * 2 );
332 OSNumber * num;
333 UInt32 index;
334 bool ret;
335
336 if( !array)
337 return( false );
338
339 LOCK();
340
341 for( index = 0; index < numElements; index++) {
342 if( (num = OSNumber::withNumber( elements[index].start,
343 8 * sizeof(IORangeScalar) ))) {
344 array->setObject(num);
345 num->release();
346 }
347 if( (num = OSNumber::withNumber( elements[index].end,
348 8 * sizeof(IORangeScalar) ))) {
349 array->setObject(num);
350 num->release();
351 }
352 }
353
354 UNLOCK();
355
356 ret = array->serialize(s);
357 array->release();
358
359 return( ret );
360}
361
362IORangeScalar IORangeAllocator::getFreeCount( void )
363{
364 UInt32 index;
365 IORangeScalar sum = 0;
366
367 for( index = 0; index < numElements; index++)
368 sum += elements[index].end - elements[index].start + 1;
369
370 return( sum );
371}
372