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