/ CFPlugIn_Factory.c
CFPlugIn_Factory.c
1 /* 2 * Copyright (c) 2015 Apple 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 /* CFPlugIn_Factory.c 25 Copyright (c) 1999-2014, Apple Inc. All rights reserved. 26 Responsibility: Tony Parker 27 */ 28 29 #include "CFBundle_Internal.h" 30 #include "CFInternal.h" 31 32 static CFTypeID __kCFPFactoryTypeID = _kCFRuntimeNotATypeID; 33 34 struct __CFPFactory { 35 CFRuntimeBase _base; 36 37 CFUUIDRef _uuid; 38 Boolean _enabled; 39 char _padding[3]; 40 41 CFPlugInFactoryFunction _func; 42 43 CFPlugInRef _plugIn; 44 CFStringRef _funcName; 45 46 CFMutableArrayRef _types; 47 CFLock_t _lock; 48 }; 49 50 static void _CFPFactoryDeallocate(CFTypeRef factory); 51 52 static const CFRuntimeClass __CFPFactoryClass = { 53 0, 54 "_CFPFactory", 55 NULL, // init 56 NULL, // copy 57 _CFPFactoryDeallocate, 58 NULL, // equal 59 NULL, // hash 60 NULL, // formatting desc 61 NULL, // debug desc 62 }; 63 64 CF_PRIVATE void __CFPFactoryInitialize(void) { 65 static dispatch_once_t initOnce; 66 dispatch_once(&initOnce, ^{ __kCFPFactoryTypeID = _CFRuntimeRegisterClass(&__CFPFactoryClass); }); 67 } 68 69 static CFTypeID _CFPFactoryGetTypeID(void) { 70 return __kCFPFactoryTypeID; 71 } 72 73 static CFLock_t CFPlugInGlobalDataLock = CFLockInit; 74 static CFMutableDictionaryRef _factoriesByFactoryID = NULL; /* Value is _CFPFactoryRef */ 75 static CFMutableDictionaryRef _factoriesByTypeID = NULL; /* Value is array of _CFPFactoryRef */ 76 77 static void _CFPFactoryAddToTable(_CFPFactoryRef factory) { 78 __CFLock(&factory->_lock); 79 CFUUIDRef uuid = (CFUUIDRef)CFRetain(factory->_uuid); 80 CFRetain(factory); 81 __CFUnlock(&factory->_lock); 82 83 __CFLock(&CFPlugInGlobalDataLock); 84 if (!_factoriesByFactoryID) { 85 CFDictionaryValueCallBacks _factoryDictValueCallbacks = {0, NULL, NULL, NULL, NULL}; 86 _factoriesByFactoryID = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &_factoryDictValueCallbacks); 87 } 88 CFDictionarySetValue(_factoriesByFactoryID, uuid, factory); 89 __CFUnlock(&CFPlugInGlobalDataLock); 90 91 if (uuid) CFRelease(uuid); 92 CFRelease(factory); 93 } 94 95 static void _CFPFactoryRemoveFromTable(_CFPFactoryRef factory) { 96 __CFLock(&factory->_lock); 97 CFUUIDRef uuid = factory->_uuid; 98 if (uuid) CFRetain(uuid); 99 __CFUnlock(&factory->_lock); 100 101 __CFLock(&CFPlugInGlobalDataLock); 102 if (uuid && _factoriesByTypeID) CFDictionaryRemoveValue(_factoriesByFactoryID, uuid); 103 __CFUnlock(&CFPlugInGlobalDataLock); 104 105 if (uuid) CFRelease(uuid); 106 } 107 108 CF_PRIVATE _CFPFactoryRef _CFPFactoryFind(CFUUIDRef factoryID, Boolean enabled) { 109 _CFPFactoryRef result = NULL; 110 111 __CFLock(&CFPlugInGlobalDataLock); 112 if (_factoriesByFactoryID) { 113 result = (_CFPFactoryRef )CFDictionaryGetValue(_factoriesByFactoryID, factoryID); 114 if (result && result->_enabled != enabled) result = NULL; 115 } 116 __CFUnlock(&CFPlugInGlobalDataLock); 117 return result; 118 } 119 120 static void _CFPFactoryDeallocate(CFTypeRef ty) { 121 SInt32 c; 122 _CFPFactoryRef factory = (_CFPFactoryRef)ty; 123 124 _CFPFactoryRemoveFromTable(factory); 125 126 if (factory->_plugIn) { 127 _CFPlugInRemoveFactory(factory->_plugIn, factory); 128 CFRelease(factory->_plugIn); 129 } 130 131 /* Remove all types for this factory. */ 132 c = CFArrayGetCount(factory->_types); 133 while (c-- > 0) _CFPFactoryRemoveType(factory, (CFUUIDRef)CFArrayGetValueAtIndex(factory->_types, c)); 134 CFRelease(factory->_types); 135 136 if (factory->_funcName) CFRelease(factory->_funcName); 137 if (factory->_uuid) CFRelease(factory->_uuid); 138 } 139 140 static _CFPFactoryRef _CFPFactoryCommonCreate(CFAllocatorRef allocator, CFUUIDRef factoryID) { 141 _CFPFactoryRef factory; 142 uint32_t size; 143 size = sizeof(struct __CFPFactory) - sizeof(CFRuntimeBase); 144 factory = (_CFPFactoryRef)_CFRuntimeCreateInstance(allocator, _CFPFactoryGetTypeID(), size, NULL); 145 if (!factory) return NULL; 146 147 factory->_uuid = (CFUUIDRef)CFRetain(factoryID); 148 factory->_enabled = true; 149 factory->_types = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks); 150 factory->_lock = CFLockInit; // WARNING: grab global lock before this lock 151 152 _CFPFactoryAddToTable(factory); 153 154 return factory; 155 } 156 157 CF_PRIVATE _CFPFactoryRef _CFPFactoryCreate(CFAllocatorRef allocator, CFUUIDRef factoryID, CFPlugInFactoryFunction func) { 158 _CFPFactoryRef factory = _CFPFactoryCommonCreate(allocator, factoryID); 159 160 __CFLock(&factory->_lock); 161 factory->_func = func; 162 factory->_plugIn = NULL; 163 factory->_funcName = NULL; 164 __CFUnlock(&factory->_lock); 165 166 return factory; 167 } 168 169 CF_PRIVATE _CFPFactoryRef _CFPFactoryCreateByName(CFAllocatorRef allocator, CFUUIDRef factoryID, CFPlugInRef plugIn, CFStringRef funcName) { 170 _CFPFactoryRef factory = _CFPFactoryCommonCreate(allocator, factoryID); 171 172 __CFLock(&factory->_lock); 173 factory->_func = NULL; 174 factory->_plugIn = (CFPlugInRef)CFRetain(plugIn); 175 if (plugIn) _CFPlugInAddFactory(plugIn, factory); 176 factory->_funcName = (funcName ? (CFStringRef)CFStringCreateCopy(allocator, funcName) : NULL); 177 __CFUnlock(&factory->_lock); 178 179 return factory; 180 } 181 182 CF_PRIVATE CFUUIDRef _CFPFactoryCopyFactoryID(_CFPFactoryRef factory) { 183 __CFLock(&factory->_lock); 184 CFUUIDRef uuid = factory->_uuid; 185 if (uuid) CFRetain(uuid); 186 __CFUnlock(&factory->_lock); 187 return uuid; 188 } 189 190 CF_PRIVATE CFPlugInRef _CFPFactoryCopyPlugIn(_CFPFactoryRef factory) { 191 __CFLock(&factory->_lock); 192 CFPlugInRef result = factory->_plugIn; 193 if (result) CFRetain(result); 194 __CFUnlock(&factory->_lock); 195 return result; 196 } 197 198 CF_PRIVATE void *_CFPFactoryCreateInstance(CFAllocatorRef allocator, _CFPFactoryRef factory, CFUUIDRef typeID) { 199 void *result = NULL; 200 201 __CFLock(&factory->_lock); 202 if (factory->_enabled) { 203 if (!factory->_func) { 204 factory->_func = (CFPlugInFactoryFunction)CFBundleGetFunctionPointerForName(factory->_plugIn, factory->_funcName); 205 if (!factory->_func) CFLog(__kCFLogPlugIn, CFSTR("Cannot find function pointer %@ for factory %@ in %@"), factory->_funcName, factory->_uuid, factory->_plugIn); 206 } 207 if (factory->_func) { 208 // UPPGOOP 209 CFPlugInFactoryFunction f = factory->_func; 210 __CFUnlock(&factory->_lock); 211 FAULT_CALLBACK((void **)&(f)); 212 result = (void *)INVOKE_CALLBACK2(f, allocator, typeID); 213 __CFLock(&factory->_lock); 214 } 215 } else { 216 CFLog(__kCFLogPlugIn, CFSTR("Factory %@ is disabled"), factory->_uuid); 217 } 218 __CFUnlock(&factory->_lock); 219 220 return result; 221 } 222 223 CF_PRIVATE void _CFPFactoryDisable(_CFPFactoryRef factory) { 224 __CFLock(&factory->_lock); 225 factory->_enabled = false; 226 __CFUnlock(&factory->_lock); 227 CFRelease(factory); 228 } 229 230 CF_PRIVATE void _CFPFactoryFlushFunctionCache(_CFPFactoryRef factory) { 231 /* MF:!!! Assert that this factory belongs to a plugIn. */ 232 /* This is called by the factory's plugIn when the plugIn unloads its code. */ 233 __CFLock(&factory->_lock); 234 factory->_func = NULL; 235 __CFUnlock(&factory->_lock); 236 } 237 238 CF_PRIVATE void _CFPFactoryAddType(_CFPFactoryRef factory, CFUUIDRef typeID) { 239 /* Add the factory to the type's array of factories */ 240 __CFLock(&factory->_lock); 241 /* Add the type to the factory's type list */ 242 CFArrayAppendValue(factory->_types, typeID); 243 __CFUnlock(&factory->_lock); 244 245 __CFLock(&CFPlugInGlobalDataLock); 246 if (!_factoriesByTypeID) _factoriesByTypeID = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 247 CFMutableArrayRef array = (CFMutableArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID); 248 if (!array) { 249 CFArrayCallBacks _factoryArrayCallbacks = {0, NULL, NULL, NULL, NULL}; 250 // Create this from default allocator 251 array = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &_factoryArrayCallbacks); 252 CFDictionarySetValue(_factoriesByTypeID, typeID, array); 253 CFRelease(array); 254 } 255 CFArrayAppendValue(array, factory); 256 __CFUnlock(&CFPlugInGlobalDataLock); 257 } 258 259 CF_PRIVATE void _CFPFactoryRemoveType(_CFPFactoryRef factory, CFUUIDRef typeID) { 260 /* Remove it from the factory's type list */ 261 SInt32 idx; 262 263 __CFLock(&factory->_lock); 264 idx = CFArrayGetFirstIndexOfValue(factory->_types, CFRangeMake(0, CFArrayGetCount(factory->_types)), typeID); 265 if (idx >= 0) CFArrayRemoveValueAtIndex(factory->_types, idx); 266 __CFUnlock(&factory->_lock); 267 268 /* Remove the factory from the type's list of factories */ 269 __CFLock(&CFPlugInGlobalDataLock); 270 if (_factoriesByTypeID) { 271 CFMutableArrayRef array = (CFMutableArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID); 272 if (array) { 273 idx = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), factory); 274 if (idx >= 0) { 275 CFArrayRemoveValueAtIndex(array, idx); 276 if (CFArrayGetCount(array) == 0) CFDictionaryRemoveValue(_factoriesByTypeID, typeID); 277 } 278 } 279 } 280 __CFUnlock(&CFPlugInGlobalDataLock); 281 } 282 283 CF_PRIVATE Boolean _CFPFactorySupportsType(_CFPFactoryRef factory, CFUUIDRef typeID) { 284 SInt32 idx; 285 286 __CFLock(&factory->_lock); 287 idx = CFArrayGetFirstIndexOfValue(factory->_types, CFRangeMake(0, CFArrayGetCount(factory->_types)), typeID); 288 __CFUnlock(&factory->_lock); 289 290 return (idx >= 0 ? true : false); 291 } 292 293 CF_PRIVATE CFArrayRef _CFPFactoryFindCopyForType(CFUUIDRef typeID) { 294 CFArrayRef result = NULL; 295 __CFLock(&CFPlugInGlobalDataLock); 296 if (_factoriesByTypeID) { 297 result = (CFArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID); 298 if (result) CFRetain(result); 299 } 300 __CFUnlock(&CFPlugInGlobalDataLock); 301 302 return result; 303 } 304 305 /* These methods are called by CFPlugInInstance when an instance is created or destroyed. If a factory's instance count goes to 0 and the factory has been disabled, the factory is destroyed. */ 306 CF_PRIVATE void _CFPFactoryAddInstance(_CFPFactoryRef factory) { 307 /* MF:!!! Assert that factory is enabled. */ 308 CFRetain(factory); 309 __CFLock(&factory->_lock); 310 CFPlugInRef plugin = factory->_plugIn; 311 if (plugin) CFRetain(plugin); 312 __CFUnlock(&factory->_lock); 313 if (plugin) { 314 _CFPlugInAddPlugInInstance(plugin); 315 CFRelease(plugin); 316 } 317 } 318 319 CF_PRIVATE void _CFPFactoryRemoveInstance(_CFPFactoryRef factory) { 320 __CFLock(&factory->_lock); 321 CFPlugInRef plugin = factory->_plugIn; 322 if (plugin) CFRetain(plugin); 323 __CFUnlock(&factory->_lock); 324 if (plugin) { 325 _CFPlugInRemovePlugInInstance(factory->_plugIn); 326 CFRelease(plugin); 327 } 328 CFRelease(factory); 329 }