]> git.saurik.com Git - apple/security.git/blame - libsecurity_utilities/lib/cfclass.cpp
Security-55179.13.tar.gz
[apple/security.git] / libsecurity_utilities / lib / cfclass.cpp
CommitLineData
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//
35CFClass::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
57uint32_t
58CFClass::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 {
106 finalizeType(cf);
107 zap = true; // the the caller to release the mutex and zap the object
108 return 0;
109 }
110 else
111 {
112 return 0;
113 }
114}
115
116uint32_t
117CFClass::refCountForType(intptr_t op, CFTypeRef cf) throw()
118{
119 uint32_t result = 0;
120 bool zap = false;
121
122 try
123 {
124 SecCFObject *obj = SecCFObject::optional(cf);
125 Mutex* mutex = obj->getMutexForObject();
126 if (mutex == NULL)
127 {
128 // if the object didn't have a mutex, it wasn't cached.
129 // Just clean it up and get out.
130 result = cleanupObject(op, cf, zap);
131 }
132 else
133 {
134 // we have a mutex, so we need to do our cleanup operation under its control
135 StLock<Mutex> _(*mutex);
136 result = cleanupObject(op, cf, zap);
137 }
138
139 if (zap) // did we release the object?
140 {
141 delete obj; // should call the overloaded delete for the object
142 }
143 }
144 catch (...)
145 {
146 }
147
148 // keep the compiler happy
149 return result;
150}
151
152
153
154void
155CFClass::finalizeType(CFTypeRef cf) throw()
156{
157 /*
158 Why are we asserting the mutex here as well as in refCountForType?
159 Because the way we control the objects and the queues are different
160 under GC than they are under non-GC operations.
161
162 In non-GC, we need to control the lifetime of the object. This means
163 that the cache lock has to be asserted while we are determining if the
164 object should live or die. The mutex is recursive, which means that
165 we won't end up with mutex inversion.
166
167 In GC, GC figures out the lifetime of the object. We probably don't need
168 to assert the mutex here, but it doesn't hurt.
169 */
170
171 SecCFObject *obj = SecCFObject::optional(cf);
172
173 bool isCollectable = CF_IS_COLLECTABLE(cf);
174
175 try
176 {
177 Mutex* mutex = obj->getMutexForObject();
178 if (mutex == NULL)
179 {
180 // if the object didn't have a mutex, it wasn't cached.
181 // Just clean it up and get out.
182 obj->aboutToDestruct(); // removes the object from its associated cache.
183 }
184 else
185 {
186 StLock<Mutex> _(*mutex);
187
188 if (obj->isNew())
189 {
190 // New objects aren't in the cache.
191 // Just clean it up and get out.
192 obj->aboutToDestruct(); // removes the object from its associated cache.
193 return;
194 }
195
196 obj->aboutToDestruct(); // removes the object from its associated cache.
197 }
198 }
199 catch(...)
200 {
201 }
202
203 if (isCollectable)
204 {
205 delete obj;
206 }
207}
208
209Boolean
210CFClass::equalType(CFTypeRef cf1, CFTypeRef cf2) throw()
211{
212 // CF checks for pointer equality and ensures type equality already
213 try {
214 return SecCFObject::optional(cf1)->equal(*SecCFObject::optional(cf2));
215 } catch (...) {
216 return false;
217 }
218}
219
220CFHashCode
221CFClass::hashType(CFTypeRef cf) throw()
222{
223 try {
224 return SecCFObject::optional(cf)->hash();
225 } catch (...) {
226 return 666; /* Beasty return for error */
227 }
228}
229
230CFStringRef
231CFClass::copyFormattingDescType(CFTypeRef cf, CFDictionaryRef dict) throw()
232{
233 try {
234 return SecCFObject::optional(cf)->copyFormattingDesc(dict);
235 } catch (...) {
236 return CFSTR("Exception thrown trying to format object");
237 }
238}
239
240CFStringRef
241CFClass::copyDebugDescType(CFTypeRef cf) throw()
242{
243 try {
244 return SecCFObject::optional(cf)->copyDebugDesc();
245 } catch (...) {
246 return CFSTR("Exception thrown trying to format object");
247 }
248}
249
250