]> git.saurik.com Git - apple/security.git/blobdiff - Security/libsecurity_cdsa_utilities/lib/handletemplates.h
Security-57031.1.35.tar.gz
[apple/security.git] / Security / libsecurity_cdsa_utilities / lib / handletemplates.h
diff --git a/Security/libsecurity_cdsa_utilities/lib/handletemplates.h b/Security/libsecurity_cdsa_utilities/lib/handletemplates.h
new file mode 100644 (file)
index 0000000..ed9da36
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2008,2011-2012 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@
+ */
+
+
+//
+// Templates to support HandleObject-like objects
+//
+#ifndef _H_HANDLETEMPLATES
+#define _H_HANDLETEMPLATES
+
+#include <security_utilities/refcount.h>
+#include <security_utilities/threading.h>
+#include <security_utilities/globalizer.h>
+#include <security_cdsa_utilities/cssmerrors.h>
+#include <vector>
+
+#if __GNUC__ > 2
+#include <ext/hash_map>
+using __gnu_cxx::hash_map;
+#else
+#include <hash_map>
+#endif
+
+namespace Security
+{
+
+//
+// A TypedHandle is a trivial mixin class whose only feature is that
+// it has a *handle* whose type is of the caller's choosing.  Subclasses 
+// need to assign such a handle during creation.
+//
+template <class _Handle>
+struct TypedHandle
+{
+public:
+    typedef _Handle Handle;
+    
+    static const _Handle invalidHandle = 0;
+
+    _Handle handle() const     { return mMyHandle; }
+    bool validHandle() const  { return mValid; }
+
+protected:
+    TypedHandle(_Handle h);
+    TypedHandle();
+
+    void setHandle(_Handle h)
+    {
+        assert(!mValid);    // guard against redefinition
+        mMyHandle = h;
+        mValid = true;
+    }
+    void clearHandle()
+    {
+        assert(mValid);
+        mValid = false;
+    }
+    
+private:
+    _Handle mMyHandle;           // our handle value
+    bool mValid;                // is the handle (still) valid?
+};
+
+//
+// MappingHandle wraps a map indexed by handles of the chosen type.  
+// A MappingHandle makes up its own handle based on some mechanism that you 
+// know nothing about.
+//
+// Please be very careful about the limits of the object contract here.
+// We promise to invent a suitable, unique handle for each MappingHandle in
+// existence within one address space. We promise that if you hand that 
+// handle to the various MappingHandle<>::find() variants, we will give you 
+// back the MappingHandle that created it. We promise to throw if you pass
+// a bad handle to those MappingHandle<>::find() variants. This is the
+// entire contract. 
+//
+template <class _Handle>
+class MappingHandle : public TypedHandle<_Handle>
+{
+protected:
+    class State;
+    
+public: 
+    typedef typename TypedHandle<_Handle>::Handle Handle;
+    virtual ~MappingHandle()
+    {
+        State &st = state();
+        StLock<Mutex> _(st);
+        st.erase(this);
+    }
+
+    template <class SubType>
+    static SubType &find(_Handle handle, CSSM_RETURN error);
+
+       template <class Subtype>
+       static Subtype &findAndLock(_Handle handle, CSSM_RETURN error);
+       
+       template <class Subtype>
+       static Subtype &findAndKill(_Handle handle, CSSM_RETURN error);
+       
+       template <class Subtype>
+       static RefPointer<Subtype> findRef(_Handle handle, CSSM_RETURN error);
+
+       template <class Subtype>
+       static RefPointer<Subtype> findRefAndLock(_Handle handle, CSSM_RETURN error);
+
+       template <class Subtype>
+       static RefPointer<Subtype> findRefAndKill(_Handle handle, CSSM_RETURN error);
+    
+    // @@@  Remove when 4003540 is fixed
+    template <class Subtype>
+    static void findAllRefs(std::vector<_Handle> &refs) {
+        state().template findAllRefs<Subtype>(refs);
+    }
+    
+protected:
+    virtual void lock();
+    virtual bool tryLock();
+    
+    typedef hash_map<_Handle, MappingHandle<_Handle> *> HandleMap;
+
+    MappingHandle();
+
+    class State : public Mutex, public HandleMap
+    {
+    public:
+        State();
+        uint32_t nextSeq()  { return ++sequence; }
+
+        bool handleInUse(_Handle h);
+        MappingHandle<_Handle> *find(_Handle h, CSSM_RETURN error);
+        typename HandleMap::iterator locate(_Handle h, CSSM_RETURN error);
+        void add(_Handle h, MappingHandle<_Handle> *obj);
+        void erase(MappingHandle<_Handle> *obj);
+        void erase(typename HandleMap::iterator &it);
+        // @@@  Remove when 4003540 is fixed
+        template <class SubType> void findAllRefs(std::vector<_Handle> &refs);
+
+    private:
+        uint32_t sequence;
+    };
+    
+private:
+    // 
+    // Create the handle to be used by the map
+    //
+    void make();
+
+    static ModuleNexus<typename MappingHandle<_Handle>::State> state;
+};
+
+//
+// MappingHandle class methods
+// Type-specific ways to access the map in various ways
+//
+template <class _Handle>
+template <class Subclass>
+inline Subclass &MappingHandle<_Handle>::find(_Handle handle, CSSM_RETURN error)
+{
+    Subclass *sub;
+    if (!(sub = dynamic_cast<Subclass *>(state().find(handle, error))))
+        CssmError::throwMe(error);
+    return *sub;
+}
+
+template <class _Handle>
+template <class Subclass>
+inline Subclass &MappingHandle<_Handle>::findAndLock(_Handle handle,
+                                             CSSM_RETURN error)
+{
+    for (;;) {
+        typename HandleMap::iterator it = state().locate(handle, error);
+        StLock<Mutex> _(state(), true);        // locate() locked it
+        Subclass *sub;
+        if (!(sub = dynamic_cast<Subclass *>(it->second)))
+            CssmError::throwMe(error); // bad type
+        if (it->second->tryLock())             // try to lock it
+            return *sub;                               // okay, go
+        Thread::yield();                               // object lock failed, backoff and retry
+    }
+}
+
+template <class _Handle>
+template <class Subclass>
+inline Subclass &MappingHandle<_Handle>::findAndKill(_Handle handle,
+                                             CSSM_RETURN error)
+{
+    for (;;) {
+        typename HandleMap::iterator it = state().locate(handle, error);
+        StLock<Mutex> _(state(), true);        // locate() locked it
+        Subclass *sub;
+        if (!(sub = dynamic_cast<Subclass *>(it->second)))
+            CssmError::throwMe(error); // bad type
+        if (it->second->tryLock()) {   // try to lock it
+            state().erase(it);                 // kill the handle
+            return *sub;                               // okay, go
+        }
+        Thread::yield();                               // object lock failed, backoff and retry
+    }
+}
+
+template <class _Handle>
+template <class Subclass>
+inline RefPointer<Subclass> MappingHandle<_Handle>::findRef(_Handle handle,
+                                                    CSSM_RETURN error)
+{
+    typename HandleMap::iterator it = state().locate(handle, error);
+    StLock<Mutex> _(state(), true); // locate() locked it
+    Subclass *sub;
+    if (!(sub = dynamic_cast<Subclass *>(it->second)))
+        CssmError::throwMe(error);
+    return sub;
+}
+
+template <class _Handle>
+template <class Subclass>
+inline RefPointer<Subclass> MappingHandle<_Handle>::findRefAndLock(_Handle handle,
+                                                           CSSM_RETURN error)
+{
+    for (;;) {
+        typename HandleMap::iterator it = state().locate(handle, error);
+        StLock<Mutex> _(state(), true);        // locate() locked it
+        Subclass *sub;
+        if (!(sub = dynamic_cast<Subclass *>(it->second)))
+            CssmError::throwMe(error); // bad type
+        if (it->second->tryLock())             // try to lock it
+            return sub;                                // okay, go
+        Thread::yield();                               // object lock failed, backoff and retry
+    }
+}
+
+template <class _Handle>
+template <class Subclass>
+inline RefPointer<Subclass> MappingHandle<_Handle>::findRefAndKill(_Handle handle,
+                                                           CSSM_RETURN error)
+{
+    for (;;) {
+        typename HandleMap::iterator it = state().locate(handle, error);
+        StLock<Mutex> _(state(), true);        // locate() locked it
+        Subclass *sub;
+        if (!(sub = dynamic_cast<Subclass *>(it->second)))
+            CssmError::throwMe(error); // bad type
+        if (it->second->tryLock()) {   // try to lock it
+            state().erase(it);                 // kill the handle
+            return sub;                                        // okay, go
+        }
+        Thread::yield();                               // object lock failed, backoff and retry
+    }
+}
+    
+//
+// @@@  Remove when 4003540 is fixed
+//
+// This is a hack to fix 3981388 and should NOT be used elsewhere.  
+// Also, do not follow this code's example: State methods should not 
+// implement type-specific behavior.  
+//
+template <class _Handle>
+template <class Subtype>
+void MappingHandle<_Handle>::State::findAllRefs(std::vector<_Handle> &refs)
+{
+    StLock<Mutex> _(*this);
+    typename HandleMap::iterator it = (*this).begin();
+    for (; it != (*this).end(); ++it)
+    {
+        Subtype *obj = dynamic_cast<Subtype *>(it->second);
+        if (obj)
+            refs.push_back(it->first);
+    }
+}
+
+
+} // end namespace Security
+
+#endif //_H_HANDLETEMPLATES