]> git.saurik.com Git - apple/security.git/blobdiff - libsecurity_utilities/lib/cfclass.cpp
Security-55163.44.tar.gz
[apple/security.git] / libsecurity_utilities / lib / cfclass.cpp
diff --git a/libsecurity_utilities/lib/cfclass.cpp b/libsecurity_utilities/lib/cfclass.cpp
new file mode 100644 (file)
index 0000000..cfd8051
--- /dev/null
@@ -0,0 +1,250 @@
+ /*
+ * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved.
+ * 
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <security_utilities/cfclass.h>
+#include <security_utilities/seccfobject.h>
+#include <security_utilities/threading.h>
+#include <CoreFoundation/CFString.h>
+#include <sys/time.h>
+#include <auto_zone.h>
+#include <objc/objc-auto.h>
+
+//
+// CFClass
+//
+CFClass::CFClass(const char *name)
+{
+       // initialize the CFRuntimeClass structure
+       version = 0;
+       className = name;
+       init = NULL;
+       copy = NULL;
+       finalize = finalizeType;
+       equal = equalType;
+       hash = hashType;
+       copyFormattingDesc = copyFormattingDescType;
+       copyDebugDesc = copyDebugDescType;
+       
+    // update because we are now doing our own reference counting
+    version |= _kCFRuntimeCustomRefCount; // see ma, no hands!
+    refcount = refCountForType;
+
+       // register
+       typeID = _CFRuntimeRegisterClass(this);
+       assert(typeID != _kCFRuntimeNotATypeID);
+}
+
+uint32_t
+CFClass::cleanupObject(intptr_t op, CFTypeRef cf, bool &zap)
+{
+    // the default is to not throw away the object
+    zap = false;
+    
+    bool isGC = CF_IS_COLLECTABLE(cf);
+    
+    uint32_t currentCount;
+    SecCFObject *obj = SecCFObject::optional(cf);
+
+    uint32_t oldCount;
+    currentCount = obj->updateRetainCount(op, &oldCount);
+    
+    if (isGC)
+    {
+        auto_zone_t* zone = objc_collectableZone();
+        
+        if (op == -1 && oldCount == 0)
+        {
+            auto_zone_release(zone, (void*) cf);
+        }
+        else if (op == 1 && oldCount == 0 && currentCount == 1)
+        {
+           auto_zone_retain(zone, (void*) cf);
+        }
+        else if (op == -1 && oldCount == 1 && currentCount == 0)
+        {
+            /*
+                To prevent accidental resurrection, just pull it out of the
+                cache.
+            */
+            obj->aboutToDestruct();
+            auto_zone_release(zone, (void*) cf);
+        }
+        else if (op == 0)
+        {
+            return currentCount;
+        }
+        
+        return 0;
+    }
+
+    if (op == 0)
+    {
+        return currentCount;
+    }
+    else if (currentCount == 0)
+    {
+        finalizeType(cf);
+        zap = true; // the the caller to release the mutex and zap the object
+        return 0;
+    }
+    else 
+    {
+        return 0;
+    }
+}
+
+uint32_t
+CFClass::refCountForType(intptr_t op, CFTypeRef cf) throw()
+{
+    uint32_t result = 0;
+    bool zap = false;
+
+    try
+    {
+        SecCFObject *obj = SecCFObject::optional(cf);
+               Mutex* mutex = obj->getMutexForObject();
+               if (mutex == NULL)
+               {
+                       // if the object didn't have a mutex, it wasn't cached.
+                       // Just clean it up and get out.
+            result = cleanupObject(op, cf, zap);
+               }
+               else
+        {
+            // we have a mutex, so we need to do our cleanup operation under its control
+            StLock<Mutex> _(*mutex);
+            result = cleanupObject(op, cf, zap);
+        }
+        
+        if (zap) // did we release the object?
+        {
+            delete obj; // should call the overloaded delete for the object
+        }
+    }
+    catch (...)
+    {
+    }
+    
+    // keep the compiler happy
+    return result;
+}
+
+
+
+void
+CFClass::finalizeType(CFTypeRef cf) throw()
+{
+    /*
+        Why are we asserting the mutex here as well as in refCountForType?
+        Because the way we control the objects and the queues are different
+        under GC than they are under non-GC operations.
+        
+        In non-GC, we need to control the lifetime of the object.  This means
+        that the cache lock has to be asserted while we are determining if the
+        object should live or die.  The mutex is recursive, which means that
+        we won't end up with mutex inversion.
+        
+        In GC, GC figures out the lifetime of the object.  We probably don't need
+        to assert the mutex here, but it doesn't hurt.
+    */
+    
+    SecCFObject *obj = SecCFObject::optional(cf);
+
+       bool isCollectable = CF_IS_COLLECTABLE(cf);
+
+    try
+       {
+               Mutex* mutex = obj->getMutexForObject();
+               if (mutex == NULL)
+               {
+                       // if the object didn't have a mutex, it wasn't cached.
+                       // Just clean it up and get out.
+                       obj->aboutToDestruct(); // removes the object from its associated cache.
+               }
+               else
+        {
+            StLock<Mutex> _(*mutex);
+            
+            if (obj->isNew())
+            {
+                // New objects aren't in the cache.
+                // Just clean it up and get out.
+                obj->aboutToDestruct(); // removes the object from its associated cache.
+                return;
+            }
+            
+            obj->aboutToDestruct(); // removes the object from its associated cache.
+        }
+       }
+       catch(...)
+       {
+       }
+    
+    if (isCollectable)
+    {
+        delete obj;
+    }
+}
+
+Boolean
+CFClass::equalType(CFTypeRef cf1, CFTypeRef cf2) throw()
+{
+       // CF checks for pointer equality and ensures type equality already
+       try {
+               return SecCFObject::optional(cf1)->equal(*SecCFObject::optional(cf2));
+       } catch (...) {
+               return false;
+       }
+}
+
+CFHashCode
+CFClass::hashType(CFTypeRef cf) throw()
+{
+       try {
+               return SecCFObject::optional(cf)->hash();
+       } catch (...) {
+               return 666; /* Beasty return for error */
+       }
+}
+
+CFStringRef
+CFClass::copyFormattingDescType(CFTypeRef cf, CFDictionaryRef dict) throw()
+{
+       try {
+               return SecCFObject::optional(cf)->copyFormattingDesc(dict);
+       } catch (...) {
+               return CFSTR("Exception thrown trying to format object");
+       }
+}
+
+CFStringRef
+CFClass::copyDebugDescType(CFTypeRef cf) throw()
+{
+       try {
+               return SecCFObject::optional(cf)->copyDebugDesc();
+       } catch (...) {
+               return CFSTR("Exception thrown trying to format object");
+       }
+}
+
+