]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_utilities/lib/threading.h
Security-57337.40.85.tar.gz
[apple/security.git] / OSX / libsecurity_utilities / lib / threading.h
1 /*
2 * Copyright (c) 2000-2004,2011,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 // threading - multi-threading support
27 //
28 // Once upon a time, this file provided a system-independent abstraction layer
29 // for various thread models. These times are long gone, and we might as well
30 // admit that we're sitting on top of pthreads (plus certain other system facilities).
31 //
32 #ifndef _H_THREADING
33 #define _H_THREADING
34
35 #include <security_utilities/utilities.h>
36 #include <security_utilities/errors.h>
37 #include <security_utilities/debugging.h>
38 # include <pthread.h>
39
40 #include <security_utilities/threading_internal.h>
41
42
43 namespace Security {
44
45
46 //
47 // Potentially, debug-logging all Mutex activity can really ruin your
48 // performance day. We take some measures to reduce the impact, but if
49 // you really can't stomach any overhead, define THREAD_NDEBUG to turn
50 // (only) thread debug-logging off. NDEBUG will turn this on automatically.
51 // On the other hand, throwing out all debug code will change the ABI of
52 // Mutexi in incompatible ways. Thus, we still generate the debug-style out-of-line
53 // code even with THREAD_NDEBUG, so that debug-style code will work with us.
54 // If you want to ditch it completely, #define THREAD_CLEAN_NDEBUG.
55 //
56 #if defined(NDEBUG) || defined(THREAD_CLEAN_NDEBUG)
57 # if !defined(THREAD_NDEBUG)
58 # define THREAD_NDEBUG
59 # endif
60 #endif
61
62
63 //
64 // An abstraction of a per-thread untyped storage slot of pointer size.
65 // Do not use this in ordinary code; this is for implementing other primitives only.
66 // Use a PerThreadPointer or ThreadNexus.
67 //
68 class ThreadStoreSlot {
69 public:
70 typedef void Destructor(void *);
71 ThreadStoreSlot(Destructor *destructor = NULL);
72 ~ThreadStoreSlot();
73
74 void *get() const { return pthread_getspecific(mKey); }
75 operator void * () const { return get(); }
76 void operator = (void *value) const
77 {
78 if (int err = pthread_setspecific(mKey, value))
79 UnixError::throwMe(err);
80 }
81
82 private:
83 pthread_key_t mKey;
84 };
85
86
87 //
88 // Per-thread pointers are implemented using the pthread TLS (thread local storage)
89 // facility.
90 // Let's be clear on what gets destroyed when, here. Following the pthread lead,
91 // when a thread dies its PerThreadPointer object(s) are properly destroyed.
92 // However, if a PerThreadPointer itself is destroyed, NOTHING HAPPENS. Yes, there are
93 // reasons for this. This is not (on its face) a bug, so don't yell. But be aware...
94 //
95 template <class T>
96 class PerThreadPointer : public ThreadStoreSlot {
97 public:
98 PerThreadPointer(bool cleanup = true) : ThreadStoreSlot(cleanup ? destructor : NULL) { }
99 operator bool() const { return get() != NULL; }
100 operator T * () const { return reinterpret_cast<T *>(get()); }
101 T *operator -> () const { return static_cast<T *>(*this); }
102 T &operator * () const { return *static_cast<T *>(get()); }
103 void operator = (T *t) { ThreadStoreSlot::operator = (t); }
104
105 private:
106 static void destructor(void *element)
107 { delete reinterpret_cast<T *>(element); }
108 };
109
110
111 //
112 // Pthread Synchronization primitives.
113 // These have a common header, strictly for our convenience.
114 //
115 class LockingPrimitive {
116 protected:
117 LockingPrimitive() { }
118
119 void check(int err) { if (err) UnixError::throwMe(err); }
120 };
121
122
123 //
124 // Mutexi
125 //
126 class Mutex : public LockingPrimitive {
127 NOCOPY(Mutex)
128 friend class Condition;
129
130 public:
131 enum Type {
132 normal,
133 recursive
134 };
135
136 Mutex(); // normal
137 Mutex(Type type); // recursive
138 ~Mutex(); // destroy (must be unlocked)
139 void lock(); // lock and wait
140 bool tryLock(); // instantaneous lock (return false if busy)
141 void unlock(); // unlock (must be locked)
142
143 private:
144 pthread_mutex_t me;
145 };
146
147
148 class RecursiveMutex : public Mutex
149 {
150 public:
151 RecursiveMutex() : Mutex(recursive) {}
152 ~RecursiveMutex() {}
153 };
154
155 //
156 // Condition variables
157 //
158 class Condition : public LockingPrimitive {
159 NOCOPY(Condition)
160
161 public:
162 Condition(Mutex &mutex); // create with specific Mutex
163 ~Condition();
164 void wait(); // wait for signal
165 void signal(); // signal one
166 void broadcast(); // signal all
167
168 Mutex &mutex; // associated Mutex
169
170 private:
171 pthread_cond_t me;
172 };
173
174
175 //
176 // A CountingMutex adds a counter to a Mutex.
177 // NOTE: This is not officially a semaphore - it's an automatically managed
178 // counter married to a Mutex.
179 //
180 class CountingMutex : public Mutex {
181 public:
182 CountingMutex() : mCount(0) { }
183 ~CountingMutex() { assert(mCount == 0); }
184
185 void enter(); // lock, add one, unlock
186 bool tryEnter(); // enter or return false
187 void exit(); // lock, subtract one, unlock
188
189 // these methods do not lock - use only while you hold the lock
190 unsigned int count() const { return mCount; }
191 bool isIdle() const { return mCount == 0; }
192
193 // convert Mutex lock to CountingMutex enter/exit. Expert use only
194 void finishEnter(); // all but the initial lock
195 void finishExit(); // all but the initial lock
196
197 private:
198 unsigned int mCount; // counter level
199 };
200
201 //
202 // A ReadWriteLock is a wrapper around a pthread_rwlock
203 //
204 class ReadWriteLock : public Mutex {
205 public:
206 ReadWriteLock();
207 ~ReadWriteLock() { check(pthread_rwlock_destroy(&mLock)); }
208
209 // Takes the read lock
210 bool lock();
211 bool tryLock();
212 void unlock();
213
214 bool writeLock();
215 bool tryWriteLock();
216
217 private:
218 pthread_rwlock_t mLock;
219 };
220
221
222 //
223 // A guaranteed-unlocker stack-based class.
224 // By default, this will use lock/unlock methods, but you can provide your own
225 // alternates (to, e.g., use enter/exit, or some more specialized pair of operations).
226 //
227 // NOTE: StLock itself is not thread-safe. It is intended for use (usually on the stack)
228 // by a single thread.
229 //
230 template <class Lock,
231 void (Lock::*_lock)() = &Lock::lock,
232 void (Lock::*_unlock)() = &Lock::unlock>
233 class StLock {
234 public:
235 StLock(Lock &lck) : me(lck) { (me.*_lock)(); mActive = true; }
236 StLock(Lock &lck, bool option) : me(lck), mActive(option) { }
237 ~StLock() { if (mActive) (me.*_unlock)(); }
238
239 bool isActive() const { return mActive; }
240 void lock() { if(!mActive) { (me.*_lock)(); mActive = true; }}
241 void unlock() { if(mActive) { (me.*_unlock)(); mActive = false; }}
242 void release() { assert(mActive); mActive = false; }
243
244 operator const Lock &() const { return me; }
245
246 protected:
247 Lock &me;
248 bool mActive;
249 };
250
251 // Note: if you use the TryRead or TryWrite modes, you must check if you
252 // actually have the lock before proceeding
253 class StReadWriteLock {
254 public:
255 enum Type {
256 Read,
257 TryRead,
258 Write,
259 TryWrite
260 };
261 StReadWriteLock(ReadWriteLock &lck, Type type) : mType(type), mIsLocked(false), mRWLock(lck)
262 { lock(); }
263 ~StReadWriteLock() { if(mIsLocked) mRWLock.unlock(); }
264
265 bool lock();
266 void unlock();
267 bool isLocked();
268
269 protected:
270 Type mType;
271 bool mIsLocked;
272 ReadWriteLock& mRWLock;
273 };
274
275
276 template <class TakeLock, class ReleaseLock,
277 void (TakeLock::*_lock)() = &TakeLock::lock,
278 void (TakeLock::*_unlock)() = &TakeLock::unlock,
279 void (ReleaseLock::*_rlock)() = &ReleaseLock::lock,
280 void (ReleaseLock::*_runlock)() = &ReleaseLock::unlock>
281 class StSyncLock {
282 public:
283 StSyncLock(TakeLock &tlck, ReleaseLock &rlck) : taken(tlck), released(rlck) {
284 (released.*_unlock)();
285 (taken.*_lock)();
286 mActive = true;
287 }
288 StSyncLock(TakeLock &tlck, ReleaseLock &rlck, bool option) : taken(tlck), released(rlck), mActive(option) { }
289 ~StSyncLock() { if (mActive) { (taken.*_unlock)(); (released.*_rlock)(); }}
290
291 bool isActive() const { return mActive; }
292 void lock() { if(!mActive) { (released.*_runlock)(); (taken.*_lock)(); mActive = true; }}
293 void unlock() { if(mActive) { (taken.*_unlock)(); (released.*_rlock)(); mActive = false; }}
294 void release() { assert(mActive); mActive = false; }
295
296 protected:
297 TakeLock &taken;
298 ReleaseLock &released;
299 bool mActive;
300 };
301
302
303 //
304 // Atomic increment/decrement operations.
305 // The default implementation uses a Mutex. However, many architectures can do
306 // much better than that.
307 // Be very clear on the nature of AtomicCounter. It implies no memory barriers of
308 // any kind. This means that (1) you cannot protect any other memory region with it
309 // (use a Mutex for that), and (2) it may not enforce cross-processor ordering, which
310 // means that you have no guarantee that you'll see modifications by other processors
311 // made earlier (unless another mechanism provides the memory barrier).
312 // On the other hand, if your compiler has brains, this is blindingly fast...
313 //
314 template <class Integer = uint32_t>
315 class StaticAtomicCounter {
316 protected:
317 Integer mValue;
318
319 public:
320 operator Integer() const { return mValue; }
321
322 // infix versions (primary)
323 Integer operator ++ () { return Atomic<Integer>::increment(mValue); }
324 Integer operator -- () { return Atomic<Integer>::decrement(mValue); }
325
326 // postfix versions
327 Integer operator ++ (int) { return Atomic<Integer>::increment(mValue) - 1; }
328 Integer operator -- (int) { return Atomic<Integer>::decrement(mValue) + 1; }
329
330 // generic offset
331 Integer operator += (int delta) { return Atomic<Integer>::add(delta, mValue); }
332 };
333
334
335 template <class Integer = int>
336 class AtomicCounter : public StaticAtomicCounter<Integer> {
337 public:
338 AtomicCounter(Integer init = 0) { StaticAtomicCounter<Integer>::mValue = init; }
339 };
340
341
342 //
343 // A class implementing a separate thread of execution.
344 // Do not expect many high-level semantics to be portable. If you can,
345 // restrict yourself to expect parallel execution and little else.
346 //
347 class Thread {
348 NOCOPY(Thread)
349 public:
350 class Identity {
351 friend class Thread;
352
353 Identity(pthread_t id) : mIdent(id) { }
354 public:
355 Identity() { }
356
357 static Identity current() { return pthread_self(); }
358
359 bool operator == (const Identity &other) const
360 { return pthread_equal(mIdent, other.mIdent); }
361
362 bool operator != (const Identity &other) const
363 { return !(*this == other); }
364
365 private:
366 pthread_t mIdent;
367 };
368
369 public:
370 Thread() { } // constructor
371 virtual ~Thread(); // virtual destructor
372 void run(); // begin running the thread
373
374 public:
375 static void yield(); // unstructured short-term processor yield
376
377 protected:
378 virtual void action() = 0; // the action to be performed
379
380 private:
381 Identity self; // my own identity (instance constant)
382
383 static void *runner(void *); // argument to pthread_create
384 };
385
386
387 //
388 // A "just run this function in a thread" variant of Thread
389 //
390 class ThreadRunner : public Thread {
391 typedef void Action();
392 public:
393 ThreadRunner(Action *todo);
394
395 private:
396 void action();
397 Action *mAction;
398 };
399
400
401 } // end namespace Security
402
403 #endif //_H_THREADING