1 /* 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved. 3 * 4 * @APPLE_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. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include <security_utilities/cfclass.h> 25#include <security_utilities/seccfobject.h> 26#include <security_utilities/threading.h> 27#include <CoreFoundation/CFString.h> 28#include <sys/time.h> 29#include <auto_zone.h> 30#include <objc/objc-auto.h> 31 32// 33// CFClass 34// 35CFClass::CFClass(const char *name) 36{ 37 // initialize the CFRuntimeClass structure 38 version = 0; 39 className = name; 40 init = NULL; 41 copy = NULL; 42 finalize = finalizeType; 43 equal = equalType; 44 hash = hashType; 45 copyFormattingDesc = copyFormattingDescType; 46 copyDebugDesc = copyDebugDescType; 47 48 // update because we are now doing our own reference counting 49 version |= _kCFRuntimeCustomRefCount; // see ma, no hands! 50 refcount = refCountForType; 51 52 // register 53 typeID = _CFRuntimeRegisterClass(this); 54 assert(typeID != _kCFRuntimeNotATypeID); 55} 56 57uint32_t 58CFClass::cleanupObject(intptr_t op, CFTypeRef cf, bool &zap) 59{ 60 // the default is to not throw away the object 61 zap = false; 62 63 bool isGC = CF_IS_COLLECTABLE(cf); 64 65 uint32_t currentCount; 66 SecCFObject *obj = SecCFObject::optional(cf); 67 68 uint32_t oldCount; 69 currentCount = obj->updateRetainCount(op, &oldCount); 70 71 if (isGC) 72 { 73 auto_zone_t* zone = objc_collectableZone(); 74 75 if (op == -1 && oldCount == 0) 76 { 77 auto_zone_release(zone, (void*) cf); 78 } 79 else if (op == 1 && oldCount == 0 && currentCount == 1) 80 { 81 auto_zone_retain(zone, (void*) cf); 82 } 83 else if (op == -1 && oldCount == 1 && currentCount == 0) 84 { 85 /* 86 To prevent accidental resurrection, just pull it out of the 87 cache. 88 */ 89 obj->aboutToDestruct(); 90 auto_zone_release(zone, (void*) cf); 91 } 92 else if (op == 0) 93 { 94 return currentCount; 95 } 96 97 return 0; 98 } 99 100 if (op == 0) 101 { 102 return currentCount; 103 } 104 else if (currentCount == 0) 105 { 106 // we may not be able to delete if the caller has active children 107 if (obj->mayDelete()) 108 { 109 finalizeType(cf); 110 zap = true; // ask the caller to release the mutex and zap the object 111 return 0; 112 } 113 else 114 { 115 return currentCount; 116 } 117 } 118 else 119 { 120 return 0; 121 } 122} 123 124uint32_t 125CFClass::refCountForType(intptr_t op, CFTypeRef cf) throw() 126{ 127 uint32_t result = 0; 128 bool zap = false; 129 130 try 131 { 132 SecCFObject *obj = SecCFObject::optional(cf); 133 Mutex* mutex = obj->getMutexForObject(); 134 if (mutex == NULL) 135 { 136 // if the object didn't have a mutex, it wasn't cached. 137 // Just clean it up and get out. 138 result = cleanupObject(op, cf, zap); 139 } 140 else 141 { 142 // we have a mutex, so we need to do our cleanup operation under its control 143 StLock<Mutex> _(*mutex); 144 result = cleanupObject(op, cf, zap); 145 } 146 147 if (zap) // did we release the object? 148 { 149 delete obj; // should call the overloaded delete for the object 150 } 151 } 152 catch (...) 153 { 154 } 155 156 // keep the compiler happy 157 return result; 158} 159 160 161 162void 163CFClass::finalizeType(CFTypeRef cf) throw() 164{ 165 /* 166 Why are we asserting the mutex here as well as in refCountForType? 167 Because the way we control the objects and the queues are different 168 under GC than they are under non-GC operations. 169 170 In non-GC, we need to control the lifetime of the object. This means 171 that the cache lock has to be asserted while we are determining if the 172 object should live or die. The mutex is recursive, which means that 173 we won't end up with mutex inversion. 174 175 In GC, GC figures out the lifetime of the object. We probably don't need 176 to assert the mutex here, but it doesn't hurt. 177 */ 178 179 SecCFObject *obj = SecCFObject::optional(cf); 180 181 bool isCollectable = CF_IS_COLLECTABLE(cf); 182 183 try 184 { 185 Mutex* mutex = obj->getMutexForObject(); 186 if (mutex == NULL) 187 { 188 // if the object didn't have a mutex, it wasn't cached. 189 // Just clean it up and get out. 190 obj->aboutToDestruct(); // removes the object from its associated cache. 191 } 192 else 193 { 194 StLock<Mutex> _(*mutex); 195 196 if (obj->isNew()) 197 { 198 // New objects aren't in the cache. 199 // Just clean it up and get out. 200 obj->aboutToDestruct(); // removes the object from its associated cache. 201 return; 202 } 203 204 obj->aboutToDestruct(); // removes the object from its associated cache. 205 } 206 } 207 catch(...) 208 { 209 } 210 211 if (isCollectable) 212 { 213 delete obj; 214 } 215} 216 217Boolean 218CFClass::equalType(CFTypeRef cf1, CFTypeRef cf2) throw() 219{ 220 // CF checks for pointer equality and ensures type equality already 221 try { 222 return SecCFObject::optional(cf1)->equal(*SecCFObject::optional(cf2)); 223 } catch (...) { 224 return false; 225 } 226} 227 228CFHashCode 229CFClass::hashType(CFTypeRef cf) throw() 230{ 231 try { 232 return SecCFObject::optional(cf)->hash(); 233 } catch (...) { 234 return 666; /* Beasty return for error */ 235 } 236} 237 238CFStringRef 239CFClass::copyFormattingDescType(CFTypeRef cf, CFDictionaryRef dict) throw() 240{ 241 try { 242 return SecCFObject::optional(cf)->copyFormattingDesc(dict); 243 } catch (...) { 244 return CFSTR("Exception thrown trying to format object"); 245 } 246} 247 248CFStringRef 249CFClass::copyDebugDescType(CFTypeRef cf) throw() 250{ 251 try { 252 return SecCFObject::optional(cf)->copyDebugDesc(); 253 } catch (...) { 254 return CFSTR("Exception thrown trying to format object"); 255 } 256} 257 258 259