]>
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 #if !defined(THREAD_CLEAN_NDEBUG) 
  29 # define THREAD_MAKE_STUBS 
  31 #include <Security/threading.h> 
  35 // Thread-local storage primitive 
  37 #if _USE_THREADS == _USE_PTHREADS 
  39 ThreadStoreSlot::ThreadStoreSlot(Destructor 
*destructor
) 
  41     if (int err 
= pthread_key_create(&mKey
, destructor
)) 
  42         UnixError::throwMe(err
); 
  45 ThreadStoreSlot::~ThreadStoreSlot() 
  47     //@@@ if we wanted to dispose of pending task objects, we'd have 
  48     //@@@ to keep a set of them and delete them explicitly here 
  49     pthread_key_delete(mKey
); 
  56 // Mutex implementation 
  58 #if _USE_THREADS == _USE_PTHREADS 
  60 #if !defined(THREAD_CLEAN_NDEBUG) 
  62 bool Mutex::debugHasInitialized
; 
  63 bool Mutex::loggingMutexi
; 
  65 Mutex::Mutex(bool log
) 
  67 #if !defined(THREAD_NDEBUG) 
  68         // this debug-setup code isn't interlocked, but it's idempotent 
  69         // (don't worry, be happy) 
  70         if (!debugHasInitialized
) { 
  71                 loggingMutexi 
= Debug::debugging("mutex"); 
  72                 debugHasInitialized 
= true; 
  74         debugLog 
= log 
&& loggingMutexi
; 
  75     useCount 
= contentionCount 
= 0; 
  78 #endif //THREAD_NDEBUG     
  79         check(pthread_mutex_init(&me
, NULL
)); 
  84 #if !defined(THREAD_NDEBUG) 
  85         if (debugLog 
&& (useCount 
> 100 || contentionCount 
> 0)) 
  86                 debug("mutex", "%p destroyed after %ld/%ld locks/contentions", this, useCount
, contentionCount
); 
  87 #endif //THREAD_NDEBUG 
  88         check(pthread_mutex_destroy(&me
)); 
  93 #if !defined(THREAD_NDEBUG) 
  96                 switch (int err 
= pthread_mutex_trylock(&me
)) { 
 101                                 debug("mutex", "%p contended (%ld of %ld)", this, ++contentionCount
, useCount
); 
 102                         check(pthread_mutex_lock(&me
)); 
 105                         UnixError::throwMe(err
); 
 107                 if (useCount 
% 100 == 0) 
 108                         debug("mutex", "%p locked %ld", this, useCount
); 
 110                         debug("mutex", "%p locked", this); 
 113 #endif //THREAD_NDEBUG 
 114         check(pthread_mutex_lock(&me
)); 
 117 bool Mutex::tryLock() 
 120         if (int err 
= pthread_mutex_trylock(&me
)) { 
 122                         UnixError::throwMe(err
); 
 123 #if !defined(THREAD_NDEBUG) 
 125                         debug("mutex", "%p trylock contended (%ld of %ld)", 
 126                                 this, ++contentionCount
, useCount
); 
 127 #endif //THREAD_NDEBUG 
 130 #if !defined(THREAD_NDEBUG) 
 132                 if (useCount 
% 100 == 0) 
 133                         debug("mutex", "%p locked %ld", this, useCount
); 
 135                         debug("mutex", "%p locked", this); 
 136 #endif //THREAD_NDEBUG 
 142 #if !defined(MUTEX_NDEBUG) 
 144                 debug("mutex", "%p unlocked", this); 
 145 #endif //MUTEX_NDEBUG 
 146         check(pthread_mutex_unlock(&me
)); 
 149 #endif //!THREAD_CLEAN_NDEBUG 
 154 // CountingMutex implementation. 
 155 // Note that this is a generic implementation based on a specific Mutex type. 
 156 // In other words, it should work no matter how Mutex is implemented. 
 157 // Also note that CountingMutex is expected to interlock properly with Mutex, 
 158 // so you canNOT just use an AtomicCounter here. 
 160 void CountingMutex::enter() 
 164     debug("mutex", "%p up to %d", this, mCount
); 
 168 bool CountingMutex::tryEnter()           
 173     debug("mutex", "%p up to %d (was try)", this, mCount
); 
 178 void CountingMutex::exit() 
 183     debug("mutex", "%p down to %d", this, mCount
); 
 187 void CountingMutex::finishEnter() 
 190     debug("mutex", "%p finish up to %d", this, mCount
); 
 194 void CountingMutex::finishExit() 
 198     debug("mutex", "%p finish down to %d", this, mCount
); 
 205 // Threads implementation 
 207 #if _USE_THREADS == _USE_PTHREADS 
 215     if (int err 
= pthread_create(&self
.mIdent
, NULL
, runner
, this)) 
 216         UnixError::throwMe(err
); 
 217         debug("thread", "%p created", self
.mIdent
); 
 220 void *Thread::runner(void *arg
) 
 222     Thread 
*me 
= static_cast<Thread 
*>(arg
); 
 223     if (int err 
= pthread_detach(me
->self
.mIdent
)) 
 224         UnixError::throwMe(err
); 
 225         debug("thread", "%p starting", me
->self
.mIdent
); 
 227         debug("thread", "%p terminating", me
->self
.mIdent
); 
 239 #include <Security/memutils.h> 
 241 void Thread::Identity::getIdString(char id
[idLength
]) 
 243         pthread_t current 
= pthread_self(); 
 244         // We're not supposed to know what a pthread_t is. Just print the first few bytes... 
 245         // (On MacOS X, it's a pointer to a pthread_t internal structure, so this works fine.) 
 247         memcpy(&p
, ¤t
, sizeof(p
)); 
 248         snprintf(id
, idLength
, "%lx", long(p
)); 
 257 // ThreadRunner implementation 
 259 ThreadRunner::ThreadRunner(Action 
*todo
) 
 265 void ThreadRunner::action() 
 273 // This implementation uses mWait as a "sloppy" wait blocker (only). 
 274 // It should be a semaphore of course, but we don't have a semaphore 
 275 // abstraction right now. The authoritative locking protocol is based on mLock. 
 277 NestingMutex::NestingMutex() : mCount(0) 
 280 void NestingMutex::lock() 
 288 bool NestingMutex::tryLock() 
 290     StLock
<Mutex
> _(mLock
); 
 291     if (mCount 
== 0) {  // initial lock 
 293         mIdent 
= Thread::Identity::current(); 
 296     } else if (mIdent 
== Thread::Identity::current()) { // recursive lock 
 299     } else {    // locked by another thread 
 304 void NestingMutex::unlock() 
 306     StLock
<Mutex
> _(mLock
); 
 307     assert(mCount 
> 0 && mIdent 
== Thread::Identity::current()); 
 308     if (--mCount 
== 0)  // last recursive unlock