]> git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_utilities/globalizer.h
Security-29.tar.gz
[apple/security.git] / cdsa / cdsa_utilities / globalizer.h
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 /*
20 * globalizer - multiscope globalization services
21 */
22 #ifndef _H_GLOBALIZER
23 #define _H_GLOBALIZER
24
25 #include <Security/threading.h>
26 #include <memory>
27
28 #ifdef _CPP_GLOBALIZER
29 # pragma export on
30 #endif
31
32 namespace Security
33 {
34
35 //
36 // GlobalNexus is the common superclass of all globality scopes.
37 // A Nexus is an *access point* to the *single* object of a given
38 // type in the Nexus's particular scope.
39 //
40 class GlobalNexus {
41 public:
42 class Error : public exception {
43 public:
44 virtual ~Error();
45 const char * const message;
46 Error(const char *m) : message(m) { }
47 const char *what() const { return message; }
48 };
49 };
50
51
52 //
53 // A module-scope nexus is tied to the linker Nexus object itself.
54 // Its scope is all code accessing that particular Nexus object
55 // from within a process. Any number of ModuleNexus objects can
56 // exist, and each implements a different scope.
57 //
58 // IMPORTANT notes on this class can be found in globalizer.cpp.
59 // DO NOT change anything here before carefully reading them.
60 //
61 #if defined(_HAVE_ATOMIC_OPERATIONS)
62
63 class ModuleNexusCommon : public GlobalNexus {
64 protected:
65 AtomicWord create(void *(*make)());
66
67 protected:
68 // both of these will be statically initialized to zero
69 AtomicWord pointer;
70 StaticAtomicCounter<uint32> sync;
71 };
72
73 template <class Type>
74 class ModuleNexus : public ModuleNexusCommon {
75 public:
76 Type &operator () ()
77 {
78 AtomicWord p = pointer; // latch pointer
79 return *reinterpret_cast<Type *>((p && !(p & 0x1)) ? p : create(make));
80 }
81
82 void reset()
83 {
84 if (pointer && !(pointer & 0x1)) {
85 delete reinterpret_cast<Type *>(pointer);
86 pointer = 0;
87 }
88 }
89
90 private:
91 static void *make() { return new Type; }
92 };
93
94 #else // !_HAVE_ATOMIC_OPERATIONS
95
96 template <class Type>
97 class ModuleNexus : public GlobalNexus {
98 public:
99 Type &operator () ()
100 {
101 #if !defined(PTHREAD_STRICT)
102 // not strictly kosher POSIX, but pointers are usually atomic types
103 if (mSingleton)
104 return *mSingleton;
105 #endif
106 StLock<Mutex> _(mLock);
107 if (mSingleton == NULL)
108 mSingleton = new Type;
109 return *mSingleton;
110 }
111
112 void reset() { delete mSingleton; mSingleton = NULL; }
113
114 private:
115 Type *mSingleton; // pointer to singleton static initialized to NULL
116 Mutex mLock; // construction lock
117 };
118
119 #endif // _HAVE_ATOMIC_OPERATIONS
120
121 template <class Type>
122 class CleanModuleNexus : public ModuleNexus<Type> {
123 public:
124 ~CleanModuleNexus()
125 {
126 debug("nexus", "ModuleNexus %p destroyed object 0x%x", this, pointer);
127 delete reinterpret_cast<Type *>(pointer);
128 }
129 };
130
131
132 //
133 // A thread-scope nexus is tied to a particular native thread AND
134 // a particular nexus object. Its scope is all code in any one thread
135 // that access that particular Nexus object. Any number of Nexus objects
136 // can exist, and each implements a different scope for each thread.
137 // NOTE: ThreadNexus is dynamically constructed. If you want static,
138 // zero-initialization ThreadNexi, put them inside a ModuleNexus.
139 //
140 #if _USE_THREADS == _USE_PTHREADS
141
142 template <class Type>
143 class ThreadNexus : public GlobalNexus {
144 public:
145 ThreadNexus() : mSlot(true) { }
146 Type &operator () ()
147 {
148 // no thread contention here!
149 if (Type *p = mSlot)
150 return *p;
151 mSlot = new Type;
152 return *mSlot;
153 }
154
155 private:
156 PerThreadPointer<Type> mSlot;
157 };
158
159 #endif //_USE_PTHREADS
160
161
162 //
163 // A ProcessNexus is global within a single process, regardless of
164 // load module boundaries. You can have any number of ProcessNexus
165 // scopes, each identified by a C string (compared by value, not pointer).
166 //
167 class ProcessNexusBase : public GlobalNexus {
168 protected:
169 ProcessNexusBase(const char *identifier);
170
171 struct Store {
172 void *mObject;
173 Mutex mLock;
174 };
175 Store *mStore;
176 };
177
178 template <class Type>
179 class ProcessNexus : public ProcessNexusBase {
180 public:
181 ProcessNexus(const char *identifier) : ProcessNexusBase(identifier) { }
182 Type &operator () ();
183
184 private:
185 Type *mObject;
186 };
187
188 template <class Type>
189 Type &ProcessNexus<Type>::operator () ()
190 {
191 #if !defined(PTHREAD_STRICT)
192 // not strictly kosher POSIX, but pointers are usually atomic types
193 if (mStore->mObject)
194 return *reinterpret_cast<Type *>(mStore->mObject);
195 #endif
196 StLock<Mutex> _(mStore->mLock);
197 if (mStore->mObject == NULL)
198 mStore->mObject = new Type;
199 return *reinterpret_cast<Type *>(mStore->mObject);
200 };
201
202
203 } // end namespace Security
204
205 #endif //_H_GLOBALIZER