]> git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_utilities/threading.h
Security-179.tar.gz
[apple/security.git] / cdsa / cdsa_utilities / threading.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 // threading - generic thread support
21 //
22 #ifndef _H_THREADING
23 #define _H_THREADING
24
25 #include <Security/utilities.h>
26 #include <Security/debugging.h>
27
28 #if _USE_THREADS == _USE_PTHREADS
29 # include <pthread.h>
30 #endif
31
32 #include <Security/threading_internal.h>
33
34
35 namespace Security {
36
37
38 //
39 // Potentially, debug-logging all Mutex activity can really ruin your
40 // performance day. We take some measures to reduce the impact, but if
41 // you really can't stomach any overhead, define THREAD_NDEBUG to turn
42 // (only) thread debug-logging off. NDEBUG will turn this on automatically.
43 // On the other hand, throwing out all debug code will change the ABI of
44 // Mutexi in incompatible ways. Thus, we still generate the debug-style out-of-line
45 // code even with THREAD_NDEBUG, so that debug-style code will work with us.
46 // If you want to ditch it completely, #define THREAD_CLEAN_NDEBUG.
47 //
48 #if defined(NDEBUG) || defined(THREAD_CLEAN_NDEBUG)
49 # if !defined(THREAD_NDEBUG)
50 # define THREAD_NDEBUG
51 # endif
52 #endif
53
54
55 //
56 // An abstraction of a per-thread untyped storage slot of pointer size.
57 // Do not use this in ordinary code; this is for implementing other primitives only.
58 // Use a PerThreadPointer or ThreadNexus.
59 //
60 #if _USE_THREADS == _USE_PTHREADS
61
62 class ThreadStoreSlot {
63 public:
64 typedef void Destructor(void *);
65 ThreadStoreSlot(Destructor *destructor = NULL);
66 ~ThreadStoreSlot();
67
68 void *get() const { return pthread_getspecific(mKey); }
69 operator void * () const { return get(); }
70 void operator = (void *value) const
71 {
72 if (int err = pthread_setspecific(mKey, value))
73 UnixError::throwMe(err);
74 }
75
76 private:
77 pthread_key_t mKey;
78 };
79
80 #endif //_USE_PTHREADS
81
82
83 //
84 // Per-thread pointers are patterned after the pthread TLS (thread local storage)
85 // facility.
86 // Let's be clear on what gets destroyed when, here. Following the pthread lead,
87 // when a thread dies its PerThreadPointer object(s) are properly destroyed.
88 // However, if a PerThreadPointer itself is destroyed, NOTHING HAPPENS. Yes, there are
89 // reasons for this. This is not (on its face) a bug, so don't yell. But be aware...
90 //
91 #if _USE_THREADS == _USE_PTHREADS
92
93 template <class T>
94 class PerThreadPointer : public ThreadStoreSlot {
95 public:
96 PerThreadPointer(bool cleanup = true) : ThreadStoreSlot(cleanup ? destructor : NULL) { }
97 operator bool() const { return get() != NULL; }
98 operator T * () const { return reinterpret_cast<T *>(get()); }
99 T *operator -> () const { return static_cast<T *>(*this); }
100 T &operator * () const { return *static_cast<T *>(get()); }
101 void operator = (T *t) { ThreadStoreSlot::operator = (t); }
102
103 private:
104 static void destructor(void *element)
105 { delete reinterpret_cast<T *>(element); }
106 };
107
108 #elif _USE_THREADS == _USE_NO_THREADS
109
110 template <class T>
111 class PerThreadPointer {
112 public:
113 PerThreadPointer(bool cleanup = true) : mCleanup(cleanup) { }
114 ~PerThreadPointer() { /* no cleanup - see comment above */ }
115 operator bool() const { return mValue != NULL; }
116 operator T * () const { return mValue; }
117 T *operator -> () const { return mValue; }
118 T &operator * () const { assert(mValue); return *mValue; }
119 void operator = (T *t) { mValue = t; }
120
121 private:
122 T *mValue;
123 bool mCleanup;
124 };
125
126 #else
127 # error Unsupported threading model
128 #endif //_USE_THREADS
129
130
131 //
132 // Basic Mutex operations.
133 // This will be some as-cheap-as-feasible locking primitive that only
134 // controls one bit (locked/unlocked), plus whatever you contractually
135 // put under its control.
136 //
137 #if _USE_THREADS == _USE_PTHREADS
138
139 class Mutex {
140 NOCOPY(Mutex)
141
142 void check(int err) { if (err) UnixError::throwMe(err); }
143
144 public:
145 enum Type {
146 normal,
147 recursive
148 };
149
150 Mutex(bool log = true);
151 Mutex(Type type, bool log = true);
152 ~Mutex();
153 void lock();
154 bool tryLock();
155 void unlock();
156
157 private:
158 pthread_mutex_t me;
159
160 bool debugLog; // log *this* mutex
161 unsigned long useCount; // number of locks succeeded
162 unsigned long contentionCount; // number of contentions (valid only if debugLog)
163 static bool debugHasInitialized; // global: debug state set up
164 static bool loggingMutexi; // global: we are debug-logging mutexi
165
166 void init(Type type, bool log);
167 };
168
169 #elif _USE_THREADS == _USE_NO_THREADS
170
171 class Mutex {
172 public:
173 void lock(bool = true) { }
174 void unlock() { }
175 bool tryLock() { return true; }
176 };
177
178 #else
179 # error Unsupported threading model
180 #endif //_USE_THREADS
181
182
183 //
184 // A CountingMutex adds a counter to a Mutex.
185 // NOTE: This is not officially a semaphore, even if it happens to be implemented with
186 // one on some platforms.
187 //
188 class CountingMutex : public Mutex {
189 // note that this implementation works for any system implementing Mutex *somehow*
190 public:
191 CountingMutex() : mCount(0) { }
192 ~CountingMutex() { assert(mCount == 0); }
193
194 void enter();
195 bool tryEnter();
196 void exit();
197
198 // these methods do not lock - use only while you hold the lock
199 unsigned int count() const { return mCount; }
200 bool isIdle() const { return mCount == 0; }
201
202 // convert Mutex lock to CountingMutex enter/exit. Expert use only
203 void finishEnter();
204 void finishExit();
205
206 private:
207 unsigned int mCount;
208 };
209
210
211 //
212 // A guaranteed-unlocker stack-based class.
213 // By default, this will use lock/unlock methods, but you can provide your own
214 // alternates (to, e.g., use enter/exit, or some more specialized pair of operations).
215 //
216 // NOTE: StLock itself is not thread-safe. It is intended for use (usually on the stack)
217 // by a single thread.
218 //
219 template <class Lock,
220 void (Lock::*_lock)() = &Lock::lock,
221 void (Lock::*_unlock)() = &Lock::unlock>
222 class StLock {
223 public:
224 StLock(Lock &lck) : me(lck) { (me.*_lock)(); mActive = true; }
225 StLock(Lock &lck, bool option) : me(lck), mActive(option) { }
226 ~StLock() { if (mActive) (me.*_unlock)(); }
227
228 bool isActive() const { return mActive; }
229 void lock() { if(!mActive) { (me.*_lock)(); mActive = true; }}
230 void unlock() { if(mActive) { (me.*_unlock)(); mActive = false; }}
231 void release() { assert(mActive); mActive = false; }
232
233 operator const Lock &() const { return me; }
234
235 protected:
236 Lock &me;
237 bool mActive;
238 };
239
240
241 //
242 // Atomic increment/decrement operations.
243 // The default implementation uses a Mutex. However, many architectures can do
244 // much better than that.
245 // Be very clear on the nature of AtomicCounter. It implies no memory barriers of
246 // any kind. This means that (1) you cannot protect any other memory region with it
247 // (use a Mutex for that), and (2) it may not enforce cross-processor ordering, which
248 // means that you have no guarantee that you'll see modifications by other processors
249 // made earlier (unless another mechanism provides the memory barrier).
250 // On the other hand, if your compiler has brains, this is blindingly fast...
251 //
252 template <class Integer = int>
253 class StaticAtomicCounter {
254 protected:
255
256 #if defined(_HAVE_ATOMIC_OPERATIONS)
257 AtomicWord mValue;
258 public:
259 operator Integer() const { return mValue; }
260
261 // infix versions (primary)
262 Integer operator ++ () { return atomicIncrement(mValue); }
263 Integer operator -- () { return atomicDecrement(mValue); }
264
265 // postfix versions
266 Integer operator ++ (int) { return atomicIncrement(mValue) - 1; }
267 Integer operator -- (int) { return atomicDecrement(mValue) + 1; }
268
269 // generic offset
270 Integer operator += (int delta) { return atomicOffset(mValue, delta); }
271
272 #else // no atomic integers, use locks
273
274 Integer mValue;
275 mutable Mutex mLock;
276 public:
277 StaticAtomicCounter(Integer init = 0) : mValue(init), mLock(false) { }
278 operator Integer() const { StLock<Mutex> _(mLock); return mValue; }
279 Integer operator ++ () { StLock<Mutex> _(mLock); return ++mValue; }
280 Integer operator -- () { StLock<Mutex> _(mLock); return --mValue; }
281 Integer operator ++ (int) { StLock<Mutex> _(mLock); return mValue++; }
282 Integer operator -- (int) { StLock<Mutex> _(mLock); return mValue--; }
283 Integer operator += (int delta) { StLock<Mutex> _(mLock); return mValue += delta; }
284 #endif
285 };
286
287
288 template <class Integer = int>
289 class AtomicCounter : public StaticAtomicCounter<Integer> {
290 public:
291 AtomicCounter(Integer init = 0) { mValue = 0; }
292 };
293
294
295 //
296 // A class implementing a separate thread of execution.
297 // Do not expect many high-level semantics to be portable. If you can,
298 // restrict yourself to expect parallel execution and little else.
299 //
300 #if _USE_THREADS == _USE_PTHREADS
301
302 class Thread {
303 NOCOPY(Thread)
304 public:
305 class Identity {
306 friend class Thread;
307
308 Identity(pthread_t id) : mIdent(id) { }
309 public:
310 Identity() { }
311
312 static Identity current() { return pthread_self(); }
313
314 bool operator == (const Identity &other) const
315 { return pthread_equal(mIdent, other.mIdent); }
316
317 bool operator != (const Identity &other) const
318 { return !(*this == other); }
319
320 // visible thread identifiers are FOR DEBUGGING ONLY
321 // if you use this for production code, your code will rot after shipment :-)
322 static const int idLength = 10;
323 static void getIdString(char id[idLength]);
324
325 private:
326 pthread_t mIdent;
327 };
328
329 public:
330 Thread() { } // constructor
331 virtual ~Thread(); // virtual destructor
332 void run(); // begin running the thread
333
334 public:
335 static void yield(); // unstructured short-term processor yield
336
337 protected:
338 virtual void action() = 0; // the action to be performed
339
340 private:
341 Identity self; // my own identity (instance constant)
342
343 static void *runner(void *); // argument to pthread_create
344 };
345
346 #elif _USE_THREADS == _USE_NO_THREADS
347
348 class Thread {
349 NOCOPY(Thread)
350 public:
351 Thread() { } // constructor
352 virtual ~Thread() { } // virtual destructor
353 void run() { action(); } // just synchronously run the action
354
355 public:
356 class Identity {
357 public:
358 static Identity current() { return Identity(); }
359
360 bool operator == (const Identity &) const { return true; } // all the same
361 bool operator != (const Identity &) const { return false; }
362
363 #if !defined(NDEBUG)
364 static const idLength = 9;
365 static void getIdString(char id[idLength]) { memcpy(id, "nothread", idLength); }
366 #endif
367
368 private:
369 Identity() { }
370 };
371
372 public:
373 void yield() { assert(false); }
374
375 protected:
376 virtual void action() = 0; // implement action of thread
377 };
378
379 #else
380 # error Unsupported threading model
381 #endif
382
383
384 //
385 // A "just run this function in a thread" variant of Thread
386 //
387 class ThreadRunner : public Thread {
388 typedef void Action();
389 public:
390 ThreadRunner(Action *todo);
391
392 private:
393 void action();
394 Action *mAction;
395 };
396
397
398 //
399 // A NestingMutex allows recursive re-entry by the same thread.
400 // Some pthread implementations support this through a mutex attribute.
401 // OSX's doesn't, naturally. This implementation works on all pthread platforms.
402 //
403 class NestingMutex {
404 public:
405 NestingMutex();
406
407 void lock();
408 bool tryLock();
409 void unlock();
410
411 private:
412 Mutex mLock;
413 Mutex mWait;
414 Thread::Identity mIdent;
415 uint32 mCount;
416 };
417
418 } // end namespace Security
419
420 #endif //_H_THREADING