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