1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. |
3 | * |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
5 | * |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License |
8 | * Version 2.0 (the 'License'). You may not use this file except in |
9 | * compliance with the License. The rights granted to you under the License |
10 | * may not be used to create, or enable the creation or redistribution of, |
11 | * unlawful or unlicensed copies of an Apple operating system, or to |
12 | * circumvent, violate, or enable the circumvention or violation of, any |
13 | * terms of an Apple operating system software license agreement. |
14 | * |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. |
17 | * |
18 | * The Original Code and all software distributed under the License are |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
23 | * Please see the License for the specific language governing rights and |
24 | * limitations under the License. |
25 | * |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
27 | */ |
28 | /* IOArray.h created by rsulack on Thu 11-Sep-1997 */ |
29 | |
30 | #define IOKIT_ENABLE_SHARED_PTR |
31 | |
32 | #include <libkern/c++/OSArray.h> |
33 | #include <libkern/c++/OSCollection.h> |
34 | #include <libkern/c++/OSCollectionIterator.h> |
35 | #include <libkern/c++/OSLib.h> |
36 | #include <libkern/c++/OSSharedPtr.h> |
37 | |
38 | #define super OSIterator |
39 | |
40 | OSDefineMetaClassAndStructors(OSCollectionIterator, OSIterator) |
41 | |
42 | bool |
43 | OSCollectionIterator::initWithCollection(const OSCollection *inColl) |
44 | { |
45 | if (!super::init() || !inColl) { |
46 | return false; |
47 | } |
48 | |
49 | collection.reset(p: inColl, OSRetain); |
50 | collIterator = NULL; |
51 | initialUpdateStamp = 0; |
52 | valid = false; |
53 | |
54 | return true; |
55 | } |
56 | |
57 | OSSharedPtr<OSCollectionIterator> |
58 | OSCollectionIterator::withCollection(const OSCollection *inColl) |
59 | { |
60 | OSSharedPtr<OSCollectionIterator> me = OSMakeShared<OSCollectionIterator>(); |
61 | |
62 | if (me && !me->initWithCollection(inColl)) { |
63 | return nullptr; |
64 | } |
65 | |
66 | return me; |
67 | } |
68 | |
69 | void |
70 | OSCollectionIterator::free() |
71 | { |
72 | freeIteratorStorage(); |
73 | |
74 | collection.reset(); |
75 | |
76 | super::free(); |
77 | } |
78 | |
79 | void |
80 | OSCollectionIterator::reset() |
81 | { |
82 | valid = false; |
83 | bool initialized = initializeIteratorStorage(); |
84 | |
85 | if (!initialized) { |
86 | // reusing existing storage |
87 | void * storage = getIteratorStorage(); |
88 | bzero(s: storage, n: collection->iteratorSize()); |
89 | |
90 | if (!collection->initIterator(iterationContext: storage)) { |
91 | return; |
92 | } |
93 | |
94 | initialUpdateStamp = collection->updateStamp; |
95 | valid = true; |
96 | } |
97 | } |
98 | |
99 | bool |
100 | OSCollectionIterator::isValid() |
101 | { |
102 | initializeIteratorStorage(); |
103 | |
104 | if (!valid || collection->updateStamp != initialUpdateStamp) { |
105 | return false; |
106 | } |
107 | |
108 | return true; |
109 | } |
110 | |
111 | bool |
112 | OSCollectionIterator::initializeIteratorStorage() |
113 | { |
114 | void * result = NULL; |
115 | bool initialized = false; |
116 | |
117 | #if __LP64__ |
118 | OSCollectionIteratorStorageType storageType = getStorageType(); |
119 | switch (storageType) { |
120 | case OSCollectionIteratorStorageUnallocated: |
121 | if (collection->iteratorSize() > sizeof(inlineStorage) || isSubclassed()) { |
122 | collIterator = (void *)kalloc_data(collection->iteratorSize(), Z_WAITOK); |
123 | OSCONTAINER_ACCUMSIZE(collection->iteratorSize()); |
124 | if (!collection->initIterator(iterationContext: collIterator)) { |
125 | kfree_data(collIterator, collection->iteratorSize()); |
126 | OSCONTAINER_ACCUMSIZE(-((size_t) collection->iteratorSize())); |
127 | collIterator = NULL; |
128 | initialized = false; |
129 | setStorageType(OSCollectionIteratorStorageUnallocated); |
130 | } else { |
131 | setStorageType(OSCollectionIteratorStoragePointer); |
132 | result = collIterator; |
133 | initialized = true; |
134 | } |
135 | } else { |
136 | bzero(s: &inlineStorage[0], n: collection->iteratorSize()); |
137 | if (!collection->initIterator(iterationContext: &inlineStorage[0])) { |
138 | bzero(s: &inlineStorage[0], n: collection->iteratorSize()); |
139 | initialized = false; |
140 | setStorageType(OSCollectionIteratorStorageUnallocated); |
141 | } else { |
142 | setStorageType(OSCollectionIteratorStorageInline); |
143 | result = &inlineStorage[0]; |
144 | initialized = true; |
145 | } |
146 | } |
147 | break; |
148 | case OSCollectionIteratorStoragePointer: |
149 | // already initialized |
150 | initialized = false; |
151 | break; |
152 | case OSCollectionIteratorStorageInline: |
153 | // already initialized |
154 | initialized = false; |
155 | break; |
156 | default: |
157 | panic("unexpected storage type %u" , storageType); |
158 | } |
159 | #else |
160 | if (!collIterator) { |
161 | collIterator = (void *)kalloc_data(collection->iteratorSize(), Z_WAITOK); |
162 | OSCONTAINER_ACCUMSIZE(collection->iteratorSize()); |
163 | if (!collection->initIterator(collIterator)) { |
164 | kfree_data(collIterator, collection->iteratorSize()); |
165 | OSCONTAINER_ACCUMSIZE(-((size_t) collection->iteratorSize())); |
166 | collIterator = NULL; |
167 | initialized = false; |
168 | setStorageType(OSCollectionIteratorStorageUnallocated); |
169 | } else { |
170 | setStorageType(OSCollectionIteratorStoragePointer); |
171 | result = collIterator; |
172 | initialized = true; |
173 | } |
174 | } |
175 | #endif /* __LP64__ */ |
176 | |
177 | if (initialized) { |
178 | valid = true; |
179 | initialUpdateStamp = collection->updateStamp; |
180 | } |
181 | |
182 | return initialized; |
183 | } |
184 | |
185 | void * |
186 | OSCollectionIterator::getIteratorStorage() |
187 | { |
188 | void * result = NULL; |
189 | |
190 | #if __LP64__ |
191 | OSCollectionIteratorStorageType storageType = getStorageType(); |
192 | |
193 | switch (storageType) { |
194 | case OSCollectionIteratorStorageUnallocated: |
195 | result = NULL; |
196 | break; |
197 | case OSCollectionIteratorStoragePointer: |
198 | result = collIterator; |
199 | break; |
200 | case OSCollectionIteratorStorageInline: |
201 | result = &inlineStorage[0]; |
202 | break; |
203 | default: |
204 | panic("unexpected storage type %u" , storageType); |
205 | } |
206 | #else |
207 | OSCollectionIteratorStorageType storageType __assert_only = getStorageType(); |
208 | assert(storageType == OSCollectionIteratorStoragePointer || storageType == OSCollectionIteratorStorageUnallocated); |
209 | result = collIterator; |
210 | #endif /* __LP64__ */ |
211 | |
212 | return result; |
213 | } |
214 | |
215 | void |
216 | OSCollectionIterator::freeIteratorStorage() |
217 | { |
218 | #if __LP64__ |
219 | OSCollectionIteratorStorageType storageType = getStorageType(); |
220 | |
221 | switch (storageType) { |
222 | case OSCollectionIteratorStorageUnallocated: |
223 | break; |
224 | case OSCollectionIteratorStoragePointer: |
225 | kfree_data(collIterator, collection->iteratorSize()); |
226 | OSCONTAINER_ACCUMSIZE(-((size_t) collection->iteratorSize())); |
227 | collIterator = NULL; |
228 | setStorageType(OSCollectionIteratorStorageUnallocated); |
229 | break; |
230 | case OSCollectionIteratorStorageInline: |
231 | bzero(s: &inlineStorage[0], n: collection->iteratorSize()); |
232 | setStorageType(OSCollectionIteratorStorageUnallocated); |
233 | break; |
234 | default: |
235 | panic("unexpected storage type %u" , storageType); |
236 | } |
237 | #else |
238 | if (collIterator != NULL) { |
239 | assert(getStorageType() == OSCollectionIteratorStoragePointer); |
240 | kfree_data(collIterator, collection->iteratorSize()); |
241 | OSCONTAINER_ACCUMSIZE(-((size_t) collection->iteratorSize())); |
242 | collIterator = NULL; |
243 | setStorageType(OSCollectionIteratorStorageUnallocated); |
244 | } else { |
245 | assert(getStorageType() == OSCollectionIteratorStorageUnallocated); |
246 | } |
247 | #endif /* __LP64__ */ |
248 | } |
249 | |
250 | bool |
251 | OSCollectionIterator::isSubclassed() |
252 | { |
253 | return getMetaClass() != OSCollectionIterator::metaClass; |
254 | } |
255 | |
256 | OSCollectionIteratorStorageType |
257 | OSCollectionIterator::getStorageType() |
258 | { |
259 | #if __LP64__ |
260 | // Storage type is in the most significant 2 bits of collIterator |
261 | return (OSCollectionIteratorStorageType)((uintptr_t)(collIterator) >> 62); |
262 | #else |
263 | if (collIterator != NULL) { |
264 | return OSCollectionIteratorStoragePointer; |
265 | } else { |
266 | return OSCollectionIteratorStorageUnallocated; |
267 | } |
268 | #endif /* __LP64__ */ |
269 | } |
270 | |
271 | void |
272 | OSCollectionIterator::setStorageType(OSCollectionIteratorStorageType storageType) |
273 | { |
274 | #if __LP64__ |
275 | switch (storageType) { |
276 | case OSCollectionIteratorStorageUnallocated: |
277 | if (collIterator != NULL) { |
278 | assert(getStorageType() == OSCollectionIteratorStorageInline); |
279 | collIterator = NULL; |
280 | } |
281 | break; |
282 | case OSCollectionIteratorStoragePointer: |
283 | // Should already be set |
284 | assert(collIterator != NULL); |
285 | assert(getStorageType() == OSCollectionIteratorStoragePointer); |
286 | break; |
287 | case OSCollectionIteratorStorageInline: |
288 | // Set the two most sigificant bits of collIterator to 10b |
289 | collIterator = (void *)(((uintptr_t)collIterator & ~0xC000000000000000) | ((uintptr_t)OSCollectionIteratorStorageInline << 62)); |
290 | break; |
291 | default: |
292 | panic("unexpected storage type %u" , storageType); |
293 | } |
294 | #else |
295 | switch (storageType) { |
296 | case OSCollectionIteratorStorageUnallocated: |
297 | // Should already be set |
298 | assert(collIterator == NULL); |
299 | assert(getStorageType() == OSCollectionIteratorStorageUnallocated); |
300 | break; |
301 | case OSCollectionIteratorStoragePointer: |
302 | // Should already be set |
303 | assert(collIterator != NULL); |
304 | assert(getStorageType() == OSCollectionIteratorStoragePointer); |
305 | break; |
306 | case OSCollectionIteratorStorageInline: |
307 | panic("cannot use inline storage on LP32" ); |
308 | break; |
309 | default: |
310 | panic("unexpected storage type %u" , storageType); |
311 | } |
312 | #endif /* __LP64__ */ |
313 | } |
314 | |
315 | OSObject * |
316 | OSCollectionIterator::getNextObject() |
317 | { |
318 | OSObject *retObj; |
319 | bool retVal; |
320 | void * storage; |
321 | |
322 | if (!isValid()) { |
323 | return NULL; |
324 | } |
325 | |
326 | storage = getIteratorStorage(); |
327 | assert(storage != NULL); |
328 | |
329 | retVal = collection->getNextObjectForIterator(iterationContext: storage, nextObject: &retObj); |
330 | return (retVal)? retObj : NULL; |
331 | } |
332 | |