1/* 2 * Copyright (c) 2000-2004 Apple Computer, 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 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 155// 156// Condition variables 157// 158class Condition : public LockingPrimitive { 159 NOCOPY(Condition) 160 161public: 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 170private: 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// 180class CountingMutex : public Mutex { 181public: 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 197private: 198 unsigned int mCount; // counter level 199}; 200 201 202// 203// A guaranteed-unlocker stack-based class. 204// By default, this will use lock/unlock methods, but you can provide your own 205// alternates (to, e.g., use enter/exit, or some more specialized pair of operations). 206// 207// NOTE: StLock itself is not thread-safe. It is intended for use (usually on the stack) 208// by a single thread. 209// 210template <class Lock, 211 void (Lock::*_lock)() = &Lock::lock, 212 void (Lock::*_unlock)() = &Lock::unlock> 213class StLock { 214public: 215 StLock(Lock &lck) : me(lck) { (me.*_lock)(); mActive = true; } 216 StLock(Lock &lck, bool option) : me(lck), mActive(option) { } 217 ~StLock() { if (mActive) (me.*_unlock)(); } 218 219 bool isActive() const { return mActive; } 220 void lock() { if(!mActive) { (me.*_lock)(); mActive = true; }} 221 void unlock() { if(mActive) { (me.*_unlock)(); mActive = false; }} 222 void release() { assert(mActive); mActive = false; } 223 224 operator const Lock &() const { return me; } 225 226protected: 227 Lock &me; 228 bool mActive; 229}; 230 231template <class TakeLock, class ReleaseLock, 232 void (TakeLock::*_lock)() = &TakeLock::lock, 233 void (TakeLock::*_unlock)() = &TakeLock::unlock, 234 void (ReleaseLock::*_rlock)() = &ReleaseLock::lock, 235 void (ReleaseLock::*_runlock)() = &ReleaseLock::unlock> 236class StSyncLock { 237public: 238 StSyncLock(TakeLock &tlck, ReleaseLock &rlck) : taken(tlck), released(rlck) { 239 (released.*_unlock)(); 240 (taken.*_lock)(); 241 mActive = true; 242 } 243 StSyncLock(TakeLock &tlck, ReleaseLock &rlck, bool option) : taken(tlck), released(rlck), mActive(option) { } 244 ~StSyncLock() { if (mActive) { (taken.*_unlock)(); (released.*_rlock)(); }} 245 246 bool isActive() const { return mActive; } 247 void lock() { if(!mActive) { (released.*_runlock)(); (taken.*_lock)(); mActive = true; }} 248 void unlock() { if(mActive) { (taken.*_unlock)(); (released.*_rlock)(); mActive = false; }} 249 void release() { assert(mActive); mActive = false; } 250 251protected: 252 TakeLock &taken; 253 ReleaseLock &released; 254 bool mActive; 255}; 256 257 258// 259// Atomic increment/decrement operations. 260// The default implementation uses a Mutex. However, many architectures can do 261// much better than that. 262// Be very clear on the nature of AtomicCounter. It implies no memory barriers of 263// any kind. This means that (1) you cannot protect any other memory region with it 264// (use a Mutex for that), and (2) it may not enforce cross-processor ordering, which 265// means that you have no guarantee that you'll see modifications by other processors 266// made earlier (unless another mechanism provides the memory barrier). 267// On the other hand, if your compiler has brains, this is blindingly fast... 268// 269template <class Integer = uint32_t> 270class StaticAtomicCounter { 271protected: 272 Integer mValue; 273 274public: 275 operator Integer() const { return mValue; } 276 277 // infix versions (primary) 278 Integer operator ++ () { return Atomic<Integer>::increment(mValue); } 279 Integer operator -- () { return Atomic<Integer>::decrement(mValue); } 280 281 // postfix versions 282 Integer operator ++ (int) { return Atomic<Integer>::increment(mValue) - 1; } 283 Integer operator -- (int) { return Atomic<Integer>::decrement(mValue) + 1; } 284 285 // generic offset 286 Integer operator += (int delta) { return Atomic<Integer>::add(delta, mValue); } 287}; 288 289 290template <class Integer = int> 291class AtomicCounter : public StaticAtomicCounter<Integer> { 292public: 293 AtomicCounter(Integer init = 0) { StaticAtomicCounter<Integer>::mValue = init; } 294}; 295 296 297// 298// A class implementing a separate thread of execution. 299// Do not expect many high-level semantics to be portable. If you can, 300// restrict yourself to expect parallel execution and little else. 301// 302class Thread { 303 NOCOPY(Thread) 304public: 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 private: 321 pthread_t mIdent; 322 }; 323 324public: 325 Thread() { } // constructor 326 virtual ~Thread(); // virtual destructor 327 void run(); // begin running the thread 328 329public: 330 static void yield(); // unstructured short-term processor yield 331 332protected: 333 virtual void action() = 0; // the action to be performed 334 335private: 336 Identity self; // my own identity (instance constant) 337 338 static void *runner(void *); // argument to pthread_create 339}; 340 341 342// 343// A "just run this function in a thread" variant of Thread 344// 345class ThreadRunner : public Thread { 346 typedef void Action(); 347public: 348 ThreadRunner(Action *todo); 349 350private: 351 void action(); 352 Action *mAction; 353}; 354 355 356} // end namespace Security 357 358#endif //_H_THREADING 359