]>
git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_utilities/lib/threading.h
2 * Copyright (c) 2000-2004,2011,2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 // threading - multi-threading support
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).
35 #include <security_utilities/utilities.h>
36 #include <security_utilities/errors.h>
37 #include <security_utilities/debugging.h>
40 #include <security_utilities/threading_internal.h>
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.
56 #if defined(NDEBUG) || defined(THREAD_CLEAN_NDEBUG)
57 # if !defined(THREAD_NDEBUG)
58 # define THREAD_NDEBUG
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.
68 class ThreadStoreSlot
{
70 typedef void Destructor(void *);
71 ThreadStoreSlot(Destructor
*destructor
= NULL
);
74 void *get() const { return pthread_getspecific(mKey
); }
75 operator void * () const { return get(); }
76 void operator = (void *value
) const
78 if (int err
= pthread_setspecific(mKey
, value
))
79 UnixError::throwMe(err
);
88 // Per-thread pointers are implemented using the pthread TLS (thread local storage)
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...
96 class PerThreadPointer
: public ThreadStoreSlot
{
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
); }
106 static void destructor(void *element
)
107 { delete reinterpret_cast<T
*>(element
); }
112 // Pthread Synchronization primitives.
113 // These have a common header, strictly for our convenience.
115 class LockingPrimitive
{
117 LockingPrimitive() { }
119 void check(int err
) { if (err
) UnixError::throwMe(err
); }
126 class Mutex
: public LockingPrimitive
{
128 friend class Condition
;
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)
148 class RecursiveMutex
: public Mutex
151 RecursiveMutex() : Mutex(recursive
) {}
155 class NormalMutex
: public Mutex
158 NormalMutex() : Mutex(normal
) {}
163 // Condition variables
165 class Condition
: public LockingPrimitive
{
169 Condition(Mutex
&mutex
); // create with specific Mutex
171 void wait(); // wait for signal
172 void signal(); // signal one
173 void broadcast(); // signal all
175 Mutex
&mutex
; // associated Mutex
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.
187 class CountingMutex
: public Mutex
{
189 CountingMutex() : mCount(0) { }
190 ~CountingMutex() { assert(mCount
== 0); }
192 void enter(); // lock, add one, unlock
193 bool tryEnter(); // enter or return false
194 void exit(); // lock, subtract one, unlock
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; }
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
205 unsigned int mCount
; // counter level
209 // A ReadWriteLock is a wrapper around a pthread_rwlock
211 class ReadWriteLock
: public Mutex
{
214 ~ReadWriteLock() { check(pthread_rwlock_destroy(&mLock
)); }
216 // Takes the read lock
225 pthread_rwlock_t mLock
;
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).
234 // NOTE: StLock itself is not thread-safe. It is intended for use (usually on the stack)
235 // by a single thread.
237 template <class Lock
,
238 void (Lock::*_lock
)() = &Lock::lock
,
239 void (Lock::*_unlock
)() = &Lock::unlock
>
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
)(); }
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; }
251 operator const Lock
&() const { return me
; }
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.
263 template <class Lock
,
264 void (Lock::*_lock
)() = &Lock::lock
,
265 void (Lock::*_unlock
)() = &Lock::unlock
>
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;} }
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; } }
278 operator const Lock
&() const { return me
; }
285 // Note: if you use the TryRead or TryWrite modes, you must check if you
286 // actually have the lock before proceeding
287 class StReadWriteLock
{
295 StReadWriteLock(ReadWriteLock
&lck
, Type type
) : mType(type
), mIsLocked(false), mRWLock(lck
)
297 ~StReadWriteLock() { if(mIsLocked
) unlock(); }
306 ReadWriteLock
& mRWLock
;
310 template <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
>
317 StSyncLock(TakeLock
&tlck
, ReleaseLock
&rlck
) : taken(tlck
), released(rlck
) {
318 (released
.*_unlock
)();
322 StSyncLock(TakeLock
&tlck
, ReleaseLock
&rlck
, bool option
) : taken(tlck
), released(rlck
), mActive(option
) { }
323 ~StSyncLock() { if (mActive
) { (taken
.*_unlock
)(); (released
.*_rlock
)(); }}
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; }
332 ReleaseLock
&released
;
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...
348 template <class Integer
= uint32_t>
349 class StaticAtomicCounter
{
354 operator Integer() const { return mValue
; }
356 // infix versions (primary)
357 Integer
operator ++ () { return Atomic
<Integer
>::increment(mValue
); }
358 Integer
operator -- () { return Atomic
<Integer
>::decrement(mValue
); }
361 Integer
operator ++ (int) { return Atomic
<Integer
>::increment(mValue
) - 1; }
362 Integer
operator -- (int) { return Atomic
<Integer
>::decrement(mValue
) + 1; }
365 Integer
operator += (int delta
) { return Atomic
<Integer
>::add(delta
, mValue
); }
369 template <class Integer
= int>
370 class AtomicCounter
: public StaticAtomicCounter
<Integer
> {
372 AtomicCounter(Integer init
= 0) { StaticAtomicCounter
<Integer
>::mValue
= init
; }
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.
385 Thread() { } // constructor
386 virtual ~Thread(); // virtual destructor
387 void run(); // begin running the thread
390 static void yield(); // unstructured short-term processor yield
393 virtual void action() = 0; // the action to be performed
396 static void *runner(void *); // argument to pthread_create
401 // A "just run this function in a thread" variant of Thread
403 class ThreadRunner
: public Thread
{
404 typedef void Action();
406 ThreadRunner(Action
*todo
);
414 } // end namespace Security
416 #endif //_H_THREADING