--- /dev/null
+/*
+ * Copyright (c) 2000-2004,2011,2014 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+//
+// threading - multi-threading support
+//
+// Once upon a time, this file provided a system-independent abstraction layer
+// for various thread models. These times are long gone, and we might as well
+// admit that we're sitting on top of pthreads (plus certain other system facilities).
+//
+#ifndef _H_THREADING
+#define _H_THREADING
+
+#include <security_utilities/utilities.h>
+#include <security_utilities/errors.h>
+#include <security_utilities/debugging.h>
+# include <pthread.h>
+
+#include <security_utilities/threading_internal.h>
+
+
+namespace Security {
+
+
+//
+// Potentially, debug-logging all Mutex activity can really ruin your
+// performance day. We take some measures to reduce the impact, but if
+// you really can't stomach any overhead, define THREAD_NDEBUG to turn
+// (only) thread debug-logging off. NDEBUG will turn this on automatically.
+// On the other hand, throwing out all debug code will change the ABI of
+// Mutexi in incompatible ways. Thus, we still generate the debug-style out-of-line
+// code even with THREAD_NDEBUG, so that debug-style code will work with us.
+// If you want to ditch it completely, #define THREAD_CLEAN_NDEBUG.
+//
+#if defined(NDEBUG) || defined(THREAD_CLEAN_NDEBUG)
+# if !defined(THREAD_NDEBUG)
+# define THREAD_NDEBUG
+# endif
+#endif
+
+
+//
+// An abstraction of a per-thread untyped storage slot of pointer size.
+// Do not use this in ordinary code; this is for implementing other primitives only.
+// Use a PerThreadPointer or ThreadNexus.
+//
+class ThreadStoreSlot {
+public:
+ typedef void Destructor(void *);
+ ThreadStoreSlot(Destructor *destructor = NULL);
+ ~ThreadStoreSlot();
+
+ void *get() const { return pthread_getspecific(mKey); }
+ operator void * () const { return get(); }
+ void operator = (void *value) const
+ {
+ if (int err = pthread_setspecific(mKey, value))
+ UnixError::throwMe(err);
+ }
+
+private:
+ pthread_key_t mKey;
+};
+
+
+//
+// Per-thread pointers are implemented using the pthread TLS (thread local storage)
+// facility.
+// Let's be clear on what gets destroyed when, here. Following the pthread lead,
+// when a thread dies its PerThreadPointer object(s) are properly destroyed.
+// However, if a PerThreadPointer itself is destroyed, NOTHING HAPPENS. Yes, there are
+// reasons for this. This is not (on its face) a bug, so don't yell. But be aware...
+//
+template <class T>
+class PerThreadPointer : public ThreadStoreSlot {
+public:
+ PerThreadPointer(bool cleanup = true) : ThreadStoreSlot(cleanup ? destructor : NULL) { }
+ operator bool() const { return get() != NULL; }
+ operator T * () const { return reinterpret_cast<T *>(get()); }
+ T *operator -> () const { return static_cast<T *>(*this); }
+ T &operator * () const { return *static_cast<T *>(get()); }
+ void operator = (T *t) { ThreadStoreSlot::operator = (t); }
+
+private:
+ static void destructor(void *element)
+ { delete reinterpret_cast<T *>(element); }
+};
+
+
+//
+// Pthread Synchronization primitives.
+// These have a common header, strictly for our convenience.
+//
+class LockingPrimitive {
+protected:
+ LockingPrimitive() { }
+
+ void check(int err) { if (err) UnixError::throwMe(err); }
+};
+
+
+//
+// Mutexi
+//
+class Mutex : public LockingPrimitive {
+ NOCOPY(Mutex)
+ friend class Condition;
+
+public:
+ enum Type {
+ normal,
+ recursive
+ };
+
+ Mutex(); // normal
+ Mutex(Type type); // recursive
+ ~Mutex(); // destroy (must be unlocked)
+ void lock(); // lock and wait
+ bool tryLock(); // instantaneous lock (return false if busy)
+ void unlock(); // unlock (must be locked)
+
+private:
+ pthread_mutex_t me;
+};
+
+
+class RecursiveMutex : public Mutex
+{
+public:
+ RecursiveMutex() : Mutex(recursive) {}
+ ~RecursiveMutex() {}
+};
+
+//
+// Condition variables
+//
+class Condition : public LockingPrimitive {
+ NOCOPY(Condition)
+
+public:
+ Condition(Mutex &mutex); // create with specific Mutex
+ ~Condition();
+ void wait(); // wait for signal
+ void signal(); // signal one
+ void broadcast(); // signal all
+
+ Mutex &mutex; // associated Mutex
+
+private:
+ pthread_cond_t me;
+};
+
+
+//
+// A CountingMutex adds a counter to a Mutex.
+// NOTE: This is not officially a semaphore - it's an automatically managed
+// counter married to a Mutex.
+//
+class CountingMutex : public Mutex {
+public:
+ CountingMutex() : mCount(0) { }
+ ~CountingMutex() { assert(mCount == 0); }
+
+ void enter(); // lock, add one, unlock
+ bool tryEnter(); // enter or return false
+ void exit(); // lock, subtract one, unlock
+
+ // these methods do not lock - use only while you hold the lock
+ unsigned int count() const { return mCount; }
+ bool isIdle() const { return mCount == 0; }
+
+ // convert Mutex lock to CountingMutex enter/exit. Expert use only
+ void finishEnter(); // all but the initial lock
+ void finishExit(); // all but the initial lock
+
+private:
+ unsigned int mCount; // counter level
+};
+
+
+//
+// A guaranteed-unlocker stack-based class.
+// By default, this will use lock/unlock methods, but you can provide your own
+// alternates (to, e.g., use enter/exit, or some more specialized pair of operations).
+//
+// NOTE: StLock itself is not thread-safe. It is intended for use (usually on the stack)
+// by a single thread.
+//
+template <class Lock,
+ void (Lock::*_lock)() = &Lock::lock,
+ void (Lock::*_unlock)() = &Lock::unlock>
+class StLock {
+public:
+ StLock(Lock &lck) : me(lck) { (me.*_lock)(); mActive = true; }
+ StLock(Lock &lck, bool option) : me(lck), mActive(option) { }
+ ~StLock() { if (mActive) (me.*_unlock)(); }
+
+ bool isActive() const { return mActive; }
+ void lock() { if(!mActive) { (me.*_lock)(); mActive = true; }}
+ void unlock() { if(mActive) { (me.*_unlock)(); mActive = false; }}
+ void release() { assert(mActive); mActive = false; }
+
+ operator const Lock &() const { return me; }
+
+protected:
+ Lock &me;
+ bool mActive;
+};
+
+template <class TakeLock, class ReleaseLock,
+ void (TakeLock::*_lock)() = &TakeLock::lock,
+ void (TakeLock::*_unlock)() = &TakeLock::unlock,
+ void (ReleaseLock::*_rlock)() = &ReleaseLock::lock,
+ void (ReleaseLock::*_runlock)() = &ReleaseLock::unlock>
+class StSyncLock {
+public:
+ StSyncLock(TakeLock &tlck, ReleaseLock &rlck) : taken(tlck), released(rlck) {
+ (released.*_unlock)();
+ (taken.*_lock)();
+ mActive = true;
+ }
+ StSyncLock(TakeLock &tlck, ReleaseLock &rlck, bool option) : taken(tlck), released(rlck), mActive(option) { }
+ ~StSyncLock() { if (mActive) { (taken.*_unlock)(); (released.*_rlock)(); }}
+
+ bool isActive() const { return mActive; }
+ void lock() { if(!mActive) { (released.*_runlock)(); (taken.*_lock)(); mActive = true; }}
+ void unlock() { if(mActive) { (taken.*_unlock)(); (released.*_rlock)(); mActive = false; }}
+ void release() { assert(mActive); mActive = false; }
+
+protected:
+ TakeLock &taken;
+ ReleaseLock &released;
+ bool mActive;
+};
+
+
+//
+// Atomic increment/decrement operations.
+// The default implementation uses a Mutex. However, many architectures can do
+// much better than that.
+// Be very clear on the nature of AtomicCounter. It implies no memory barriers of
+// any kind. This means that (1) you cannot protect any other memory region with it
+// (use a Mutex for that), and (2) it may not enforce cross-processor ordering, which
+// means that you have no guarantee that you'll see modifications by other processors
+// made earlier (unless another mechanism provides the memory barrier).
+// On the other hand, if your compiler has brains, this is blindingly fast...
+//
+template <class Integer = uint32_t>
+class StaticAtomicCounter {
+protected:
+ Integer mValue;
+
+public:
+ operator Integer() const { return mValue; }
+
+ // infix versions (primary)
+ Integer operator ++ () { return Atomic<Integer>::increment(mValue); }
+ Integer operator -- () { return Atomic<Integer>::decrement(mValue); }
+
+ // postfix versions
+ Integer operator ++ (int) { return Atomic<Integer>::increment(mValue) - 1; }
+ Integer operator -- (int) { return Atomic<Integer>::decrement(mValue) + 1; }
+
+ // generic offset
+ Integer operator += (int delta) { return Atomic<Integer>::add(delta, mValue); }
+};
+
+
+template <class Integer = int>
+class AtomicCounter : public StaticAtomicCounter<Integer> {
+public:
+ AtomicCounter(Integer init = 0) { StaticAtomicCounter<Integer>::mValue = init; }
+};
+
+
+//
+// A class implementing a separate thread of execution.
+// Do not expect many high-level semantics to be portable. If you can,
+// restrict yourself to expect parallel execution and little else.
+//
+class Thread {
+ NOCOPY(Thread)
+public:
+ class Identity {
+ friend class Thread;
+
+ Identity(pthread_t id) : mIdent(id) { }
+ public:
+ Identity() { }
+
+ static Identity current() { return pthread_self(); }
+
+ bool operator == (const Identity &other) const
+ { return pthread_equal(mIdent, other.mIdent); }
+
+ bool operator != (const Identity &other) const
+ { return !(*this == other); }
+
+ private:
+ pthread_t mIdent;
+ };
+
+public:
+ Thread() { } // constructor
+ virtual ~Thread(); // virtual destructor
+ void run(); // begin running the thread
+
+public:
+ static void yield(); // unstructured short-term processor yield
+
+protected:
+ virtual void action() = 0; // the action to be performed
+
+private:
+ Identity self; // my own identity (instance constant)
+
+ static void *runner(void *); // argument to pthread_create
+};
+
+
+//
+// A "just run this function in a thread" variant of Thread
+//
+class ThreadRunner : public Thread {
+ typedef void Action();
+public:
+ ThreadRunner(Action *todo);
+
+private:
+ void action();
+ Action *mAction;
+};
+
+
+} // end namespace Security
+
+#endif //_H_THREADING