blob: 9e026f1df62ba7f8578c499814f19161e9e632ef [file] [log] [blame]
/* CFPlugIn_Factory.c
Copyright (c) 1999-2016, Apple Inc. and the Swift project authors
Portions Copyright (c) 2014-2016 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See http://swift.org/LICENSE.txt for license information
See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
Responsibility: Tony Parker
*/
#include "CFBundle_Internal.h"
#include "CFInternal.h"
static CFTypeID __kCFPFactoryTypeID = _kCFRuntimeNotATypeID;
struct __CFPFactory {
CFRuntimeBase _base;
CFUUIDRef _uuid;
Boolean _enabled;
char _padding[3];
CFPlugInFactoryFunction _func;
CFPlugInRef _plugIn;
CFStringRef _funcName;
CFMutableArrayRef _types;
CFLock_t _lock;
};
static void _CFPFactoryDeallocate(CFTypeRef factory);
static const CFRuntimeClass __CFPFactoryClass = {
0,
"_CFPFactory",
NULL, // init
NULL, // copy
_CFPFactoryDeallocate,
NULL, // equal
NULL, // hash
NULL, // formatting desc
NULL, // debug desc
};
CF_PRIVATE void __CFPFactoryInitialize(void) {
static dispatch_once_t initOnce;
dispatch_once(&initOnce, ^{ __kCFPFactoryTypeID = _CFRuntimeRegisterClass(&__CFPFactoryClass); });
}
static CFTypeID _CFPFactoryGetTypeID(void) {
return __kCFPFactoryTypeID;
}
static CFLock_t CFPlugInGlobalDataLock = CFLockInit;
static CFMutableDictionaryRef _factoriesByFactoryID = NULL; /* Value is _CFPFactoryRef */
static CFMutableDictionaryRef _factoriesByTypeID = NULL; /* Value is array of _CFPFactoryRef */
static void _CFPFactoryAddToTable(_CFPFactoryRef factory) {
__CFLock(&factory->_lock);
CFUUIDRef uuid = (CFUUIDRef)CFRetain(factory->_uuid);
CFRetain(factory);
__CFUnlock(&factory->_lock);
__CFLock(&CFPlugInGlobalDataLock);
if (!_factoriesByFactoryID) {
CFDictionaryValueCallBacks _factoryDictValueCallbacks = {0, NULL, NULL, NULL, NULL};
_factoriesByFactoryID = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &_factoryDictValueCallbacks);
}
CFDictionarySetValue(_factoriesByFactoryID, uuid, factory);
__CFUnlock(&CFPlugInGlobalDataLock);
if (uuid) CFRelease(uuid);
CFRelease(factory);
}
static void _CFPFactoryRemoveFromTable(_CFPFactoryRef factory) {
__CFLock(&factory->_lock);
CFUUIDRef uuid = factory->_uuid;
if (uuid) CFRetain(uuid);
__CFUnlock(&factory->_lock);
__CFLock(&CFPlugInGlobalDataLock);
if (uuid && _factoriesByTypeID) CFDictionaryRemoveValue(_factoriesByFactoryID, uuid);
__CFUnlock(&CFPlugInGlobalDataLock);
if (uuid) CFRelease(uuid);
}
CF_PRIVATE _CFPFactoryRef _CFPFactoryFind(CFUUIDRef factoryID, Boolean enabled) {
_CFPFactoryRef result = NULL;
__CFLock(&CFPlugInGlobalDataLock);
if (_factoriesByFactoryID) {
result = (_CFPFactoryRef )CFDictionaryGetValue(_factoriesByFactoryID, factoryID);
if (result && result->_enabled != enabled) result = NULL;
}
__CFUnlock(&CFPlugInGlobalDataLock);
return result;
}
static void _CFPFactoryDeallocate(CFTypeRef ty) {
SInt32 c;
_CFPFactoryRef factory = (_CFPFactoryRef)ty;
_CFPFactoryRemoveFromTable(factory);
if (factory->_plugIn) {
_CFPlugInRemoveFactory(factory->_plugIn, factory);
CFRelease(factory->_plugIn);
}
/* Remove all types for this factory. */
c = CFArrayGetCount(factory->_types);
while (c-- > 0) _CFPFactoryRemoveType(factory, (CFUUIDRef)CFArrayGetValueAtIndex(factory->_types, c));
CFRelease(factory->_types);
if (factory->_funcName) CFRelease(factory->_funcName);
if (factory->_uuid) CFRelease(factory->_uuid);
}
static _CFPFactoryRef _CFPFactoryCommonCreate(CFAllocatorRef allocator, CFUUIDRef factoryID) {
_CFPFactoryRef factory;
uint32_t size;
size = sizeof(struct __CFPFactory) - sizeof(CFRuntimeBase);
factory = (_CFPFactoryRef)_CFRuntimeCreateInstance(allocator, _CFPFactoryGetTypeID(), size, NULL);
if (!factory) return NULL;
factory->_uuid = (CFUUIDRef)CFRetain(factoryID);
factory->_enabled = true;
factory->_types = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
factory->_lock = CFLockInit; // WARNING: grab global lock before this lock
_CFPFactoryAddToTable(factory);
return factory;
}
CF_PRIVATE _CFPFactoryRef _CFPFactoryCreate(CFAllocatorRef allocator, CFUUIDRef factoryID, CFPlugInFactoryFunction func) {
_CFPFactoryRef factory = _CFPFactoryCommonCreate(allocator, factoryID);
__CFLock(&factory->_lock);
factory->_func = func;
factory->_plugIn = NULL;
factory->_funcName = NULL;
__CFUnlock(&factory->_lock);
return factory;
}
CF_PRIVATE _CFPFactoryRef _CFPFactoryCreateByName(CFAllocatorRef allocator, CFUUIDRef factoryID, CFPlugInRef plugIn, CFStringRef funcName) {
_CFPFactoryRef factory = _CFPFactoryCommonCreate(allocator, factoryID);
__CFLock(&factory->_lock);
factory->_func = NULL;
factory->_plugIn = (CFPlugInRef)CFRetain(plugIn);
if (plugIn) _CFPlugInAddFactory(plugIn, factory);
factory->_funcName = (funcName ? (CFStringRef)CFStringCreateCopy(allocator, funcName) : NULL);
__CFUnlock(&factory->_lock);
return factory;
}
CF_PRIVATE CFUUIDRef _CFPFactoryCopyFactoryID(_CFPFactoryRef factory) {
__CFLock(&factory->_lock);
CFUUIDRef uuid = factory->_uuid;
if (uuid) CFRetain(uuid);
__CFUnlock(&factory->_lock);
return uuid;
}
CF_PRIVATE CFPlugInRef _CFPFactoryCopyPlugIn(_CFPFactoryRef factory) {
__CFLock(&factory->_lock);
CFPlugInRef result = factory->_plugIn;
if (result) CFRetain(result);
__CFUnlock(&factory->_lock);
return result;
}
CF_PRIVATE void *_CFPFactoryCreateInstance(CFAllocatorRef allocator, _CFPFactoryRef factory, CFUUIDRef typeID) {
void *result = NULL;
__CFLock(&factory->_lock);
if (factory->_enabled) {
if (!factory->_func) {
factory->_func = (CFPlugInFactoryFunction)CFBundleGetFunctionPointerForName(factory->_plugIn, factory->_funcName);
if (!factory->_func) CFLog(__kCFLogPlugIn, CFSTR("Cannot find function pointer %@ for factory %@ in %@"), factory->_funcName, factory->_uuid, factory->_plugIn);
}
if (factory->_func) {
// UPPGOOP
CFPlugInFactoryFunction f = factory->_func;
__CFUnlock(&factory->_lock);
FAULT_CALLBACK((void **)&(f));
result = (void *)INVOKE_CALLBACK2(f, allocator, typeID);
__CFLock(&factory->_lock);
}
} else {
CFLog(__kCFLogPlugIn, CFSTR("Factory %@ is disabled"), factory->_uuid);
}
__CFUnlock(&factory->_lock);
return result;
}
CF_PRIVATE void _CFPFactoryDisable(_CFPFactoryRef factory) {
__CFLock(&factory->_lock);
factory->_enabled = false;
__CFUnlock(&factory->_lock);
CFRelease(factory);
}
CF_PRIVATE void _CFPFactoryFlushFunctionCache(_CFPFactoryRef factory) {
/* MF:!!! Assert that this factory belongs to a plugIn. */
/* This is called by the factory's plugIn when the plugIn unloads its code. */
__CFLock(&factory->_lock);
factory->_func = NULL;
__CFUnlock(&factory->_lock);
}
CF_PRIVATE void _CFPFactoryAddType(_CFPFactoryRef factory, CFUUIDRef typeID) {
/* Add the factory to the type's array of factories */
__CFLock(&factory->_lock);
/* Add the type to the factory's type list */
CFArrayAppendValue(factory->_types, typeID);
__CFUnlock(&factory->_lock);
__CFLock(&CFPlugInGlobalDataLock);
if (!_factoriesByTypeID) _factoriesByTypeID = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFMutableArrayRef array = (CFMutableArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID);
if (!array) {
CFArrayCallBacks _factoryArrayCallbacks = {0, NULL, NULL, NULL, NULL};
// Create this from default allocator
array = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &_factoryArrayCallbacks);
CFDictionarySetValue(_factoriesByTypeID, typeID, array);
CFRelease(array);
}
CFArrayAppendValue(array, factory);
__CFUnlock(&CFPlugInGlobalDataLock);
}
CF_PRIVATE void _CFPFactoryRemoveType(_CFPFactoryRef factory, CFUUIDRef typeID) {
/* Remove it from the factory's type list */
SInt32 idx;
__CFLock(&factory->_lock);
idx = CFArrayGetFirstIndexOfValue(factory->_types, CFRangeMake(0, CFArrayGetCount(factory->_types)), typeID);
if (idx >= 0) CFArrayRemoveValueAtIndex(factory->_types, idx);
__CFUnlock(&factory->_lock);
/* Remove the factory from the type's list of factories */
__CFLock(&CFPlugInGlobalDataLock);
if (_factoriesByTypeID) {
CFMutableArrayRef array = (CFMutableArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID);
if (array) {
idx = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), factory);
if (idx >= 0) {
CFArrayRemoveValueAtIndex(array, idx);
if (CFArrayGetCount(array) == 0) CFDictionaryRemoveValue(_factoriesByTypeID, typeID);
}
}
}
__CFUnlock(&CFPlugInGlobalDataLock);
}
CF_PRIVATE Boolean _CFPFactorySupportsType(_CFPFactoryRef factory, CFUUIDRef typeID) {
SInt32 idx;
__CFLock(&factory->_lock);
idx = CFArrayGetFirstIndexOfValue(factory->_types, CFRangeMake(0, CFArrayGetCount(factory->_types)), typeID);
__CFUnlock(&factory->_lock);
return (idx >= 0 ? true : false);
}
CF_PRIVATE CFArrayRef _CFPFactoryFindCopyForType(CFUUIDRef typeID) {
CFArrayRef result = NULL;
__CFLock(&CFPlugInGlobalDataLock);
if (_factoriesByTypeID) {
result = (CFArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID);
if (result) CFRetain(result);
}
__CFUnlock(&CFPlugInGlobalDataLock);
return result;
}
/* 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. */
CF_PRIVATE void _CFPFactoryAddInstance(_CFPFactoryRef factory) {
/* MF:!!! Assert that factory is enabled. */
CFRetain(factory);
__CFLock(&factory->_lock);
CFPlugInRef plugin = factory->_plugIn;
if (plugin) CFRetain(plugin);
__CFUnlock(&factory->_lock);
if (plugin) {
_CFPlugInAddPlugInInstance(plugin);
CFRelease(plugin);
}
}
CF_PRIVATE void _CFPFactoryRemoveInstance(_CFPFactoryRef factory) {
__CFLock(&factory->_lock);
CFPlugInRef plugin = factory->_plugIn;
if (plugin) CFRetain(plugin);
__CFUnlock(&factory->_lock);
if (plugin) {
_CFPlugInRemovePlugInInstance(factory->_plugIn);
CFRelease(plugin);
}
CFRelease(factory);
}