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
40OSDefineMetaClassAndStructors(OSCollectionIterator, OSIterator)
41
42bool
43OSCollectionIterator::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
57OSSharedPtr<OSCollectionIterator>
58OSCollectionIterator::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
69void
70OSCollectionIterator::free()
71{
72 freeIteratorStorage();
73
74 collection.reset();
75
76 super::free();
77}
78
79void
80OSCollectionIterator::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
99bool
100OSCollectionIterator::isValid()
101{
102 initializeIteratorStorage();
103
104 if (!valid || collection->updateStamp != initialUpdateStamp) {
105 return false;
106 }
107
108 return true;
109}
110
111bool
112OSCollectionIterator::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
185void *
186OSCollectionIterator::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
215void
216OSCollectionIterator::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
250bool
251OSCollectionIterator::isSubclassed()
252{
253 return getMetaClass() != OSCollectionIterator::metaClass;
254}
255
256OSCollectionIteratorStorageType
257OSCollectionIterator::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
271void
272OSCollectionIterator::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
315OSObject *
316OSCollectionIterator::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