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 - generic thread support 27// 28#include <security_utilities/threading.h> 29#include <security_utilities/globalizer.h> 30#include <security_utilities/memutils.h> 31 32#include <unistd.h> // WWDC 2007 thread-crash workaround 33#include <syslog.h> // WWDC 2007 thread-crash workaround 34 35// 36// Thread-local storage primitive 37// 38ThreadStoreSlot::ThreadStoreSlot(Destructor *destructor) 39{ 40 if (int err = pthread_key_create(&mKey, destructor)) 41 UnixError::throwMe(err); 42} 43 44ThreadStoreSlot::~ThreadStoreSlot() 45{ 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); 49} 50 51 52// 53// Mutex implementation 54// 55struct MutexAttributes { 56 pthread_mutexattr_t recursive; 57 pthread_mutexattr_t checking; 58 59 MutexAttributes() 60 { 61 pthread_mutexattr_init(&recursive); 62 pthread_mutexattr_settype(&recursive, PTHREAD_MUTEX_RECURSIVE); 63#if !defined(NDEBUG) 64 pthread_mutexattr_init(&checking); 65 pthread_mutexattr_settype(&checking, PTHREAD_MUTEX_ERRORCHECK); 66#endif //NDEBUG 67 } 68}; 69 70static ModuleNexus<MutexAttributes> mutexAttrs; 71 72 73Mutex::Mutex() 74{ 75 check(pthread_mutex_init(&me, NULL)); 76} 77 78Mutex::Mutex(Type type) 79{ 80 switch (type) { 81 case normal: 82 check(pthread_mutex_init(&me, IFELSEDEBUG(&mutexAttrs().checking, NULL))); 83 break; 84 case recursive: // requested recursive (is also checking, always) 85 check(pthread_mutex_init(&me, &mutexAttrs().recursive)); 86 break; 87 }; 88} 89 90 91Mutex::~Mutex() 92{ 93 int result = pthread_mutex_destroy(&me); 94 check(result); 95} 96 97 98void Mutex::lock() 99{ 100 check(pthread_mutex_lock(&me)); 101} 102 103 104bool Mutex::tryLock() 105{ 106 if (int err = pthread_mutex_trylock(&me)) { 107 if (err != EBUSY) 108 UnixError::throwMe(err); 109 return false; 110 } 111 112 return true; 113} 114 115 116void Mutex::unlock() 117{ 118 int result = pthread_mutex_unlock(&me); 119 check(result); 120} 121 122 123// 124// Condition variables 125// 126Condition::Condition(Mutex &lock) : mutex(lock) 127{ 128 check(pthread_cond_init(&me, NULL)); 129} 130 131Condition::~Condition() 132{ 133 check(pthread_cond_destroy(&me)); 134} 135 136void Condition::wait() 137{ 138 check(pthread_cond_wait(&me, &mutex.me)); 139} 140 141void Condition::signal() 142{ 143 check(pthread_cond_signal(&me)); 144} 145 146void Condition::broadcast() 147{ 148 check(pthread_cond_broadcast(&me)); 149} 150 151 152// 153// CountingMutex implementation. 154// 155void CountingMutex::enter() 156{ 157 lock(); 158 mCount++; 159 secdebug("cmutex", "%p up to %d", this, mCount); 160 unlock(); 161} 162 163bool CountingMutex::tryEnter() 164{ 165 if (!tryLock()) 166 return false; 167 mCount++; 168 secdebug("cmutex", "%p up to %d (was try)", this, mCount); 169 unlock(); 170 return true; 171} 172 173void CountingMutex::exit() 174{ 175 lock(); 176 assert(mCount > 0); 177 mCount--; 178 secdebug("cmutex", "%p down to %d", this, mCount); 179 unlock(); 180} 181 182void CountingMutex::finishEnter() 183{ 184 mCount++; 185 secdebug("cmutex", "%p finish up to %d", this, mCount); 186 unlock(); 187} 188 189void CountingMutex::finishExit() 190{ 191 assert(mCount > 0); 192 mCount--; 193 secdebug("cmutex", "%p finish down to %d", this, mCount); 194 unlock(); 195} 196 197 198 199// 200// Threads implementation 201// 202Thread::~Thread() 203{ 204} 205 206void Thread::run() 207{ 208 pthread_attr_t ptattrs; 209 int err, ntries = 10; // 10 is arbitrary 210 211 if ((err = pthread_attr_init(&ptattrs)) || 212 (err = pthread_attr_setdetachstate(&ptattrs, PTHREAD_CREATE_DETACHED))) 213 { 214 syslog(LOG_ERR, "error %d setting thread detach state", err); 215 } 216 while ((err = pthread_create(&self.mIdent, &ptattrs, runner, this) && 217 --ntries)) 218 { 219 syslog(LOG_ERR, "pthread_create() error %d", err); 220 usleep(50000); // 50 ms is arbitrary 221 } 222 if (err) 223 { 224 syslog(LOG_ERR, "too many failed pthread_create() attempts"); 225 } 226 else 227 secdebug("thread", "%p created", self.mIdent); 228} 229 230void *Thread::runner(void *arg) 231{ 232 try // the top level of any running thread of execution must have a try/catch around it, 233 // otherwise it will crash if something underneath throws. 234 { 235 Thread *me = static_cast<Thread *>(arg); 236 secdebug("thread", "%p starting", me->self.mIdent); 237 me->action(); 238 secdebug("thread", "%p terminating", me->self.mIdent); 239 delete me; 240 return NULL; 241 } 242 catch (...) 243 { 244 return NULL; 245 } 246} 247 248void Thread::yield() 249{ 250 ::sched_yield(); 251} 252 253 254// 255// ThreadRunner implementation 256// 257ThreadRunner::ThreadRunner(Action *todo) 258{ 259 mAction = todo; 260 run(); 261} 262 263void ThreadRunner::action() 264{ 265 mAction(); 266} 267