]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_utilities/lib/globalizer.h
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_utilities / lib / globalizer.h
1 /*
2 * Copyright (c) 2000-2004,2011-2012,2014 Apple 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
25 /*
26 * globalizer - multiscope globalization services
27 */
28 #ifndef _H_GLOBALIZER
29 #define _H_GLOBALIZER
30
31 #include <security_utilities/threading.h>
32 #include <memory>
33 #include <set>
34 #include <dispatch/dispatch.h>
35 #include <libkern/OSAtomic.h>
36 #include <os/lock.h>
37
38 namespace Security {
39
40
41 //
42 // GlobalNexus is the common superclass of all globality scopes.
43 // A Nexus is an *access point* to the *single* object of a given
44 // type in the Nexus's particular scope.
45 //
46 class GlobalNexus {
47 public:
48 class Error : public std::exception {
49 public:
50 virtual ~Error() _NOEXCEPT;
51 const char * const message;
52 Error(const char *m) : message(m) { }
53 const char *what() const _NOEXCEPT { return message; }
54 };
55 };
56
57
58 class ModuleNexusCommon : public GlobalNexus {
59 private:
60 void do_create(void *(*make)());
61
62 protected:
63 void *create(void *(*make)());
64 void lock() {os_unfair_lock_lock(&access);}
65 void unlock() {os_unfair_lock_unlock(&access);}
66
67 protected:
68 // all of these will be statically initialized to zero
69 void *pointer;
70 dispatch_once_t once;
71 os_unfair_lock access;
72 };
73
74 template <class Type>
75 class ModuleNexus : public ModuleNexusCommon {
76 public:
77 Type &operator () ()
78 {
79 lock();
80
81 try
82 {
83 if (pointer == NULL)
84 {
85 pointer = create(make);
86 }
87
88 unlock();
89 }
90 catch (...)
91 {
92 unlock();
93 throw;
94 }
95
96 return *reinterpret_cast<Type *>(pointer);
97 }
98
99 // does the object DEFINITELY exist already?
100 bool exists() const
101 {
102 bool result;
103 lock();
104 result = pointer != NULL;
105 unlock();
106 return result;
107 }
108
109 // destroy the object (if any) and start over - not really thread-safe
110 void reset()
111 {
112 lock();
113 if (pointer != NULL)
114 {
115 delete reinterpret_cast<Type *>(pointer);
116 pointer = NULL;
117 once = 0;
118 }
119 unlock();
120 }
121
122 private:
123 static void *make() { return new Type; }
124 };
125
126 template <class Type>
127 class CleanModuleNexus : public ModuleNexus<Type> {
128 public:
129 ~CleanModuleNexus()
130 {
131 secinfo("nexus", "ModuleNexus %p destroyed object 0x%x",
132 this, ModuleNexus<Type>::pointer);
133 delete reinterpret_cast<Type *>(ModuleNexus<Type>::pointer);
134 }
135 };
136
137 typedef std::set<void*> RetentionSet;
138
139 //
140 // A thread-scope nexus is tied to a particular native thread AND
141 // a particular nexus object. Its scope is all code in any one thread
142 // that access that particular Nexus object. Any number of Nexus objects
143 // can exist, and each implements a different scope for each thread.
144 // NOTE: ThreadNexus is dynamically constructed. If you want static,
145 // zero-initialization ThreadNexi, put them inside a ModuleNexus.
146 //
147 template <class Type>
148 class ThreadNexus : public GlobalNexus {
149 public:
150 ThreadNexus() : mSlot(true) { }
151
152 Type &operator () ()
153 {
154 // no thread contention here!
155 if (Type *p = mSlot)
156 return *p;
157 mSlot = new Type;
158 return *mSlot;
159 }
160
161 private:
162 PerThreadPointer<Type> mSlot;
163 };
164
165
166 //
167 // A ProcessNexus is global within a single process, regardless of
168 // load module boundaries. You can have any number of ProcessNexus
169 // scopes, each identified by a C string (compared by value, not pointer).
170 //
171 class ProcessNexusBase : public GlobalNexus {
172 protected:
173 ProcessNexusBase(const char *identifier);
174
175 struct Store {
176 void *mObject;
177 Mutex mLock;
178 };
179 Store *mStore;
180 };
181
182 template <class Type>
183 class ProcessNexus : public ProcessNexusBase {
184 public:
185 ProcessNexus(const char *identifier) : ProcessNexusBase(identifier) { }
186 Type &operator () ();
187
188 private:
189 Type *mObject;
190 };
191
192 template <class Type>
193 Type &ProcessNexus<Type>::operator () ()
194 {
195 #if !defined(PTHREAD_STRICT)
196 // not strictly kosher POSIX, but pointers are usually atomic types
197 if (mStore->mObject)
198 return *reinterpret_cast<Type *>(mStore->mObject);
199 #endif
200 StLock<Mutex> _(mStore->mLock);
201 if (mStore->mObject == NULL)
202 mStore->mObject = new Type;
203 return *reinterpret_cast<Type *>(mStore->mObject);
204 };
205
206
207 } // end namespace Security
208
209 #endif //_H_GLOBALIZER