]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
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 | // | |
35 | CFClass::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 | ||
57 | uint32_t | |
58 | CFClass::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 | { | |
427c49bc A |
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 | } | |
b1ab9ed8 A |
117 | } |
118 | else | |
119 | { | |
120 | return 0; | |
121 | } | |
122 | } | |
123 | ||
124 | uint32_t | |
125 | CFClass::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 | ||
162 | void | |
163 | CFClass::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 | ||
217 | Boolean | |
218 | CFClass::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 | ||
228 | CFHashCode | |
229 | CFClass::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 | ||
238 | CFStringRef | |
239 | CFClass::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 | ||
248 | CFStringRef | |
249 | CFClass::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 |