]>
git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_utilities/threading.cpp
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
20 // threading - generic thread support
25 // Since we are planning to generate "stub" out of line code for threading methods,
26 // we must force THREAD_NDEBUG to off while compiling our header. Trust me.
28 #include <Security/threading.h>
29 #include <Security/globalizer.h>
30 #include <Security/memutils.h>
34 // Thread-local storage primitive
36 #if _USE_THREADS == _USE_PTHREADS
38 ThreadStoreSlot::ThreadStoreSlot(Destructor
*destructor
)
40 if (int err
= pthread_key_create(&mKey
, destructor
))
41 UnixError::throwMe(err
);
44 ThreadStoreSlot::~ThreadStoreSlot()
46 //@@@ if we wanted to dispose of pending task objects, we'd have
47 //@@@ to keep a set of them and delete them explicitly here
48 pthread_key_delete(mKey
);
55 // Mutex implementation
57 #if _USE_THREADS == _USE_PTHREADS
59 bool Mutex::debugHasInitialized
;
60 bool Mutex::loggingMutexi
;
62 inline void Mutex::init(Type type
, bool log
)
64 #if !defined(THREAD_NDEBUG)
65 // this debug-setup code isn't interlocked, but it's idempotent
66 // (don't worry, be happy)
67 if (!debugHasInitialized
) {
68 loggingMutexi
= Debug::debugging("mutex") || Debug::debugging("mutex-c");
69 debugHasInitialized
= true;
71 debugLog
= log
&& loggingMutexi
;
72 useCount
= contentionCount
= 0;
75 #endif //THREAD_NDEBUG
78 struct Recursive
: public pthread_mutexattr_t
{
81 pthread_mutexattr_init(this);
82 pthread_mutexattr_settype(this, PTHREAD_MUTEX_RECURSIVE
);
87 Mutex::Mutex(bool log
)
90 check(pthread_mutex_init(&me
, NULL
));
93 Mutex::Mutex(Type type
, bool log
)
98 check(pthread_mutex_init(&me
, NULL
));
101 static ModuleNexus
<Recursive
> recursive
;
102 check(pthread_mutex_init(&me
, &recursive()));
108 #if !defined(THREAD_NDEBUG)
110 if (contentionCount
> 0)
111 secdebug("mutex-c", "%p destroyed after %ld/%ld locks/contentions",
112 this, useCount
, contentionCount
);
113 else if (useCount
> 100)
114 secdebug("mutex", "%p destroyed after %ld locks", this, useCount
);
116 #endif //THREAD_NDEBUG
117 check(pthread_mutex_destroy(&me
));
122 #if !defined(THREAD_NDEBUG)
125 switch (int err
= pthread_mutex_trylock(&me
)) {
130 secdebug("mutex-c", "%p contended (%ld of %ld)", this, ++contentionCount
, useCount
);
131 check(pthread_mutex_lock(&me
));
134 UnixError::throwMe(err
);
136 if (useCount
% 100 == 0)
137 secdebug("mutex", "%p locked %ld", this, useCount
);
139 secdebug("mutex", "%p locked", this);
142 #endif //THREAD_NDEBUG
143 check(pthread_mutex_lock(&me
));
146 bool Mutex::tryLock()
149 if (int err
= pthread_mutex_trylock(&me
)) {
151 UnixError::throwMe(err
);
152 #if !defined(THREAD_NDEBUG)
154 secdebug("mutex-c", "%p trylock contended (%ld of %ld)",
155 this, ++contentionCount
, useCount
);
156 #endif //THREAD_NDEBUG
159 #if !defined(THREAD_NDEBUG)
161 if (useCount
% 100 == 0)
162 secdebug("mutex", "%p locked %ld", this, useCount
);
164 secdebug("mutex", "%p locked", this);
165 #endif //THREAD_NDEBUG
171 #if !defined(MUTEX_NDEBUG)
173 secdebug("mutex", "%p unlocked", this);
174 #endif //MUTEX_NDEBUG
175 check(pthread_mutex_unlock(&me
));
182 // CountingMutex implementation.
183 // Note that this is a generic implementation based on a specific Mutex type.
184 // In other words, it should work no matter how Mutex is implemented.
185 // Also note that CountingMutex is expected to interlock properly with Mutex,
186 // so you canNOT just use an AtomicCounter here.
188 void CountingMutex::enter()
192 secdebug("mutex", "%p up to %d", this, mCount
);
196 bool CountingMutex::tryEnter()
201 secdebug("mutex", "%p up to %d (was try)", this, mCount
);
206 void CountingMutex::exit()
211 secdebug("mutex", "%p down to %d", this, mCount
);
215 void CountingMutex::finishEnter()
218 secdebug("mutex", "%p finish up to %d", this, mCount
);
222 void CountingMutex::finishExit()
226 secdebug("mutex", "%p finish down to %d", this, mCount
);
233 // Threads implementation
235 #if _USE_THREADS == _USE_PTHREADS
243 if (int err
= pthread_create(&self
.mIdent
, NULL
, runner
, this))
244 UnixError::throwMe(err
);
245 secdebug("thread", "%p created", self
.mIdent
);
248 void *Thread::runner(void *arg
)
250 Thread
*me
= static_cast<Thread
*>(arg
);
251 if (int err
= pthread_detach(me
->self
.mIdent
))
252 UnixError::throwMe(err
);
253 secdebug("thread", "%p starting", me
->self
.mIdent
);
255 secdebug("thread", "%p terminating", me
->self
.mIdent
);
267 // Make a more-or-less unique string representation of a thread id.
268 // This is meant FOR DEBUGGING ONLY. Don't use this in production code.
270 void Thread::Identity::getIdString(char id
[idLength
])
272 pthread_t current
= pthread_self();
273 // We're not supposed to know what a pthread_t is. Just print the first few bytes...
274 // (On MacOS X, it's a pointer to a pthread_t internal structure, so this works fine.)
276 memcpy(&ids
, ¤t
, sizeof(ids
));
277 snprintf(id
, idLength
, "%lx", ids
);
285 // ThreadRunner implementation
287 ThreadRunner::ThreadRunner(Action
*todo
)
293 void ThreadRunner::action()
301 // This implementation uses mWait as a "sloppy" wait blocker (only).
302 // It should be a semaphore of course, but we don't have a semaphore
303 // abstraction right now. The authoritative locking protocol is based on mLock.
305 NestingMutex::NestingMutex() : mCount(0)
308 void NestingMutex::lock()
316 bool NestingMutex::tryLock()
318 StLock
<Mutex
> _(mLock
);
319 if (mCount
== 0) { // initial lock
321 mIdent
= Thread::Identity::current();
324 } else if (mIdent
== Thread::Identity::current()) { // recursive lock
327 } else { // locked by another thread
332 void NestingMutex::unlock()
334 StLock
<Mutex
> _(mLock
);
335 assert(mCount
> 0 && mIdent
== Thread::Identity::current());
336 if (--mCount
== 0) // last recursive unlock