]> git.saurik.com Git - apple/security.git/blobdiff - Security/libsecurity_utilities/lib/globalizer.h
Security-57031.1.35.tar.gz
[apple/security.git] / Security / libsecurity_utilities / lib / globalizer.h
diff --git a/Security/libsecurity_utilities/lib/globalizer.h b/Security/libsecurity_utilities/lib/globalizer.h
new file mode 100644 (file)
index 0000000..6648046
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2000-2004,2011-2012,2014 Apple 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@
+ */
+
+
+/*
+ * globalizer - multiscope globalization services
+ */
+#ifndef _H_GLOBALIZER
+#define _H_GLOBALIZER
+
+#include <security_utilities/threading.h>
+#include <memory>
+#include <set>
+#include <dispatch/dispatch.h>
+#include <libkern/OSAtomic.h>
+
+namespace Security {
+
+
+//
+// GlobalNexus is the common superclass of all globality scopes.
+// A Nexus is an *access point* to the *single* object of a given
+// type in the Nexus's particular scope.
+//
+class GlobalNexus {
+public:
+    class Error : public std::exception {
+    public:
+        virtual ~Error() throw();
+        const char * const message;
+        Error(const char *m) : message(m) { }
+        const char *what() const throw() { return message; }
+    };
+};
+
+
+class ModuleNexusCommon : public GlobalNexus {
+private:
+    void do_create(void *(*make)());
+
+protected:
+    void *create(void *(*make)());
+    void lock() {OSSpinLockLock(&access);}
+    void unlock() {OSSpinLockUnlock(&access);}
+
+protected:
+    // all of these will be statically initialized to zero
+       void *pointer;
+    dispatch_once_t once;
+    OSSpinLock access;
+};
+
+template <class Type>
+class ModuleNexus : public ModuleNexusCommon {
+public:
+    Type &operator () () 
+    {
+        lock();
+        
+        try
+        {
+            if (pointer == NULL)
+            {
+                pointer = create(make);
+            }
+            
+            unlock();
+        }
+        catch (...)
+        {
+            unlock();
+            throw;
+        }
+        
+               return *reinterpret_cast<Type *>(pointer);
+    }
+       
+       // does the object DEFINITELY exist already?
+       bool exists() const
+       {
+        bool result;
+        lock();
+        result = pointer != NULL;
+        unlock();
+        return result;
+       }
+    
+       // destroy the object (if any) and start over - not really thread-safe
+    void reset()
+    {
+        lock();
+        if (pointer != NULL)
+        {
+            delete reinterpret_cast<Type *>(pointer);
+            pointer = NULL;
+            once = 0;
+        }
+        unlock();
+    }
+    
+private:
+    static void *make() { return new Type; }
+};
+
+template <class Type>
+class CleanModuleNexus : public ModuleNexus<Type> {
+public:
+    ~CleanModuleNexus()
+    {
+        secdebug("nexus", "ModuleNexus %p destroyed object 0x%x",
+                       this, ModuleNexus<Type>::pointer);
+        delete reinterpret_cast<Type *>(ModuleNexus<Type>::pointer);
+    }
+};
+
+typedef std::set<void*> RetentionSet;
+
+//
+// A thread-scope nexus is tied to a particular native thread AND
+// a particular nexus object. Its scope is all code in any one thread
+// that access that particular Nexus object. Any number of Nexus objects
+// can exist, and each implements a different scope for each thread.
+// NOTE: ThreadNexus is dynamically constructed. If you want static,
+// zero-initialization ThreadNexi, put them inside a ModuleNexus.
+//
+template <class Type>
+class ThreadNexus : public GlobalNexus {
+public:
+    ThreadNexus() : mSlot(true) { }
+
+    Type &operator () ()
+    {
+        // no thread contention here!
+        if (Type *p = mSlot)
+            return *p;
+        mSlot = new Type;
+        return *mSlot;
+    }
+
+private:
+    PerThreadPointer<Type> mSlot;
+};
+
+
+//
+// A ProcessNexus is global within a single process, regardless of
+// load module boundaries. You can have any number of ProcessNexus
+// scopes, each identified by a C string (compared by value, not pointer).
+//
+class ProcessNexusBase : public GlobalNexus {
+protected:
+       ProcessNexusBase(const char *identifier);
+
+       struct Store {
+               void *mObject;
+               Mutex mLock;
+       };
+       Store *mStore;
+};
+
+template <class Type>
+class ProcessNexus : public ProcessNexusBase {
+public:
+       ProcessNexus(const char *identifier) : ProcessNexusBase(identifier) { }
+       Type &operator () ();
+       
+private:
+       Type *mObject;
+};
+
+template <class Type>
+Type &ProcessNexus<Type>::operator () ()
+{
+#if !defined(PTHREAD_STRICT)
+    // not strictly kosher POSIX, but pointers are usually atomic types
+    if (mStore->mObject)
+        return *reinterpret_cast<Type *>(mStore->mObject);
+#endif
+    StLock<Mutex> _(mStore->mLock);
+    if (mStore->mObject == NULL)
+        mStore->mObject = new Type;
+    return *reinterpret_cast<Type *>(mStore->mObject);
+};
+
+
+} // end namespace Security
+
+#endif //_H_GLOBALIZER