]> git.saurik.com Git - apple/security.git/blame - OSX/libsecurity_utilities/lib/threading.h
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_utilities / lib / threading.h
CommitLineData
b1ab9ed8 1/*
d8f41ccd 2 * Copyright (c) 2000-2004,2011,2014 Apple Inc. All Rights Reserved.
b1ab9ed8
A
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
43namespace 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//
68class ThreadStoreSlot {
69public:
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
82private:
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//
95template <class T>
96class PerThreadPointer : public ThreadStoreSlot {
97public:
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
105private:
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//
115class LockingPrimitive {
116protected:
117 LockingPrimitive() { }
118
119 void check(int err) { if (err) UnixError::throwMe(err); }
120};
121
122
123//
124// Mutexi
125//
126class Mutex : public LockingPrimitive {
127 NOCOPY(Mutex)
128 friend class Condition;
129
130public:
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
143private:
144 pthread_mutex_t me;
145};
146
147
148class RecursiveMutex : public Mutex
149{
150public:
151 RecursiveMutex() : Mutex(recursive) {}
152 ~RecursiveMutex() {}
153};
154
6b200bc3
A
155class NormalMutex : public Mutex
156{
157public:
158 NormalMutex() : Mutex(normal) {}
159 ~NormalMutex() {}
160};
161
b1ab9ed8
A
162//
163// Condition variables
164//
165class Condition : public LockingPrimitive {
166 NOCOPY(Condition)
167
168public:
169 Condition(Mutex &mutex); // create with specific Mutex
170 ~Condition();
171 void wait(); // wait for signal
172 void signal(); // signal one
173 void broadcast(); // signal all
174
175 Mutex &mutex; // associated Mutex
176
177private:
178 pthread_cond_t me;
179};
180
181
182//
183// A CountingMutex adds a counter to a Mutex.
184// NOTE: This is not officially a semaphore - it's an automatically managed
185// counter married to a Mutex.
186//
187class CountingMutex : public Mutex {
188public:
189 CountingMutex() : mCount(0) { }
190 ~CountingMutex() { assert(mCount == 0); }
191
192 void enter(); // lock, add one, unlock
193 bool tryEnter(); // enter or return false
194 void exit(); // lock, subtract one, unlock
195
196 // these methods do not lock - use only while you hold the lock
197 unsigned int count() const { return mCount; }
198 bool isIdle() const { return mCount == 0; }
199
200 // convert Mutex lock to CountingMutex enter/exit. Expert use only
201 void finishEnter(); // all but the initial lock
202 void finishExit(); // all but the initial lock
203
204private:
205 unsigned int mCount; // counter level
206};
e3d460c9
A
207
208//
209// A ReadWriteLock is a wrapper around a pthread_rwlock
210//
211class ReadWriteLock : public Mutex {
212public:
213 ReadWriteLock();
214 ~ReadWriteLock() { check(pthread_rwlock_destroy(&mLock)); }
215
216 // Takes the read lock
217 bool lock();
218 bool tryLock();
219 void unlock();
220
221 bool writeLock();
222 bool tryWriteLock();
223
224private:
225 pthread_rwlock_t mLock;
226};
227
b1ab9ed8
A
228
229//
230// A guaranteed-unlocker stack-based class.
231// By default, this will use lock/unlock methods, but you can provide your own
232// alternates (to, e.g., use enter/exit, or some more specialized pair of operations).
233//
234// NOTE: StLock itself is not thread-safe. It is intended for use (usually on the stack)
235// by a single thread.
236//
237template <class Lock,
238 void (Lock::*_lock)() = &Lock::lock,
239 void (Lock::*_unlock)() = &Lock::unlock>
240class StLock {
241public:
242 StLock(Lock &lck) : me(lck) { (me.*_lock)(); mActive = true; }
243 StLock(Lock &lck, bool option) : me(lck), mActive(option) { }
244 ~StLock() { if (mActive) (me.*_unlock)(); }
245
246 bool isActive() const { return mActive; }
247 void lock() { if(!mActive) { (me.*_lock)(); mActive = true; }}
248 void unlock() { if(mActive) { (me.*_unlock)(); mActive = false; }}
249 void release() { assert(mActive); mActive = false; }
250
251 operator const Lock &() const { return me; }
252
253protected:
254 Lock &me;
255 bool mActive;
256};
257
fa7225c8
A
258//
259// This class behaves exactly as StLock above, but accepts a pointer to a mutex instead of a reference.
260// If the pointer is NULL, this class does nothing. Otherwise, it behaves as StLock.
261// Try not to use this.
262//
263template <class Lock,
264void (Lock::*_lock)() = &Lock::lock,
265void (Lock::*_unlock)() = &Lock::unlock>
266class StMaybeLock {
267public:
268 StMaybeLock(Lock *lck) : me(lck), mActive(false)
269 { if(me) { (me->*_lock)(); mActive = true; } }
270 StMaybeLock(Lock *lck, bool option) : me(lck), mActive(option) { }
271 ~StMaybeLock() { if (me) { if(mActive) (me->*_unlock)(); } else {mActive = false;} }
272
273 bool isActive() const { return mActive; }
274 void lock() { if(me) { if(!mActive) { (me->*_lock)(); mActive = true; }}}
275 void unlock() { if(me) { if(mActive) { (me->*_unlock)(); mActive = false; }}}
276 void release() { if(me) { assert(mActive); mActive = false; } }
277
278 operator const Lock &() const { return me; }
279
280protected:
281 Lock *me;
282 bool mActive;
283};
284
e3d460c9
A
285// Note: if you use the TryRead or TryWrite modes, you must check if you
286// actually have the lock before proceeding
287class StReadWriteLock {
288public:
289 enum Type {
290 Read,
291 TryRead,
292 Write,
293 TryWrite
294 };
295 StReadWriteLock(ReadWriteLock &lck, Type type) : mType(type), mIsLocked(false), mRWLock(lck)
296 { lock(); }
b04fe171 297 ~StReadWriteLock() { if(mIsLocked) unlock(); }
e3d460c9
A
298
299 bool lock();
300 void unlock();
301 bool isLocked();
302
303protected:
304 Type mType;
305 bool mIsLocked;
306 ReadWriteLock& mRWLock;
307};
308
309
b1ab9ed8
A
310template <class TakeLock, class ReleaseLock,
311 void (TakeLock::*_lock)() = &TakeLock::lock,
312 void (TakeLock::*_unlock)() = &TakeLock::unlock,
313 void (ReleaseLock::*_rlock)() = &ReleaseLock::lock,
314 void (ReleaseLock::*_runlock)() = &ReleaseLock::unlock>
315class StSyncLock {
316public:
317 StSyncLock(TakeLock &tlck, ReleaseLock &rlck) : taken(tlck), released(rlck) {
318 (released.*_unlock)();
319 (taken.*_lock)();
320 mActive = true;
321 }
322 StSyncLock(TakeLock &tlck, ReleaseLock &rlck, bool option) : taken(tlck), released(rlck), mActive(option) { }
323 ~StSyncLock() { if (mActive) { (taken.*_unlock)(); (released.*_rlock)(); }}
324
325 bool isActive() const { return mActive; }
326 void lock() { if(!mActive) { (released.*_runlock)(); (taken.*_lock)(); mActive = true; }}
327 void unlock() { if(mActive) { (taken.*_unlock)(); (released.*_rlock)(); mActive = false; }}
328 void release() { assert(mActive); mActive = false; }
329
330protected:
331 TakeLock &taken;
332 ReleaseLock &released;
333 bool mActive;
334};
335
336
337//
338// Atomic increment/decrement operations.
339// The default implementation uses a Mutex. However, many architectures can do
340// much better than that.
341// Be very clear on the nature of AtomicCounter. It implies no memory barriers of
342// any kind. This means that (1) you cannot protect any other memory region with it
343// (use a Mutex for that), and (2) it may not enforce cross-processor ordering, which
344// means that you have no guarantee that you'll see modifications by other processors
345// made earlier (unless another mechanism provides the memory barrier).
346// On the other hand, if your compiler has brains, this is blindingly fast...
347//
348template <class Integer = uint32_t>
349class StaticAtomicCounter {
350protected:
351 Integer mValue;
352
353public:
354 operator Integer() const { return mValue; }
355
356 // infix versions (primary)
357 Integer operator ++ () { return Atomic<Integer>::increment(mValue); }
358 Integer operator -- () { return Atomic<Integer>::decrement(mValue); }
359
360 // postfix versions
361 Integer operator ++ (int) { return Atomic<Integer>::increment(mValue) - 1; }
362 Integer operator -- (int) { return Atomic<Integer>::decrement(mValue) + 1; }
363
364 // generic offset
365 Integer operator += (int delta) { return Atomic<Integer>::add(delta, mValue); }
366};
367
368
369template <class Integer = int>
370class AtomicCounter : public StaticAtomicCounter<Integer> {
371public:
372 AtomicCounter(Integer init = 0) { StaticAtomicCounter<Integer>::mValue = init; }
373};
374
375
376//
377// A class implementing a separate thread of execution.
378// Do not expect many high-level semantics to be portable. If you can,
379// restrict yourself to expect parallel execution and little else.
380//
381class Thread {
382 NOCOPY(Thread)
b1ab9ed8
A
383
384public:
385 Thread() { } // constructor
386 virtual ~Thread(); // virtual destructor
387 void run(); // begin running the thread
388
389public:
390 static void yield(); // unstructured short-term processor yield
391
392protected:
393 virtual void action() = 0; // the action to be performed
394
395private:
b1ab9ed8
A
396 static void *runner(void *); // argument to pthread_create
397};
398
399
400//
401// A "just run this function in a thread" variant of Thread
402//
403class ThreadRunner : public Thread {
404 typedef void Action();
405public:
406 ThreadRunner(Action *todo);
407
408private:
409 void action();
410 Action *mAction;
411};
412
413
414} // end namespace Security
415
416#endif //_H_THREADING