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(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(storage, collection->iteratorSize()); 89 90 if (!collection->initIterator(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(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(&inlineStorage[0], collection->iteratorSize()); 137 if (!collection->initIterator(&inlineStorage[0])) { 138 bzero(&inlineStorage[0], 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(&inlineStorage[0], 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(storage, &retObj); 330 return (retVal)? retObj : NULL; 331 } 332