]> git.saurik.com Git - apple/cf.git/blob - CFPlugIn_Factory.c
CF-744.tar.gz
[apple/cf.git] / CFPlugIn_Factory.c
1 /*
2 * Copyright (c) 2012 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-2012, 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 CFSpinLock_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 __private_extern__ void __CFPFactoryInitialize(void) {
65 __kCFPFactoryTypeID = _CFRuntimeRegisterClass(&__CFPFactoryClass);
66 }
67
68 static CFTypeID _CFPFactoryGetTypeID(void) {
69 return __kCFPFactoryTypeID;
70 }
71
72 static CFSpinLock_t CFPlugInGlobalDataLock = CFSpinLockInit;
73 static CFMutableDictionaryRef _factoriesByFactoryID = NULL; /* Value is _CFPFactoryRef */
74 static CFMutableDictionaryRef _factoriesByTypeID = NULL; /* Value is array of _CFPFactoryRef */
75
76 static 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
94 static 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
107 __private_extern__ _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
119 static 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
139 static _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
156 __private_extern__ _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
168 __private_extern__ _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
181 __private_extern__ 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
189 __private_extern__ 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
197 __private_extern__ 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
222 __private_extern__ void _CFPFactoryDisable(_CFPFactoryRef factory) {
223 __CFSpinLock(&factory->_lock);
224 factory->_enabled = false;
225 __CFSpinUnlock(&factory->_lock);
226 CFRelease(factory);
227 }
228
229 __private_extern__ 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
237 __private_extern__ 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
258 __private_extern__ 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
282 __private_extern__ 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
292 __private_extern__ 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. */
305 __private_extern__ 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
318 __private_extern__ 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 }