threading.cpp
1 /* 2 * Copyright (c) 2000-2004,2011-2012,2014 Apple 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 #include <utilities/debugging.h> 32 33 #include <unistd.h> // WWDC 2007 thread-crash workaround 34 #include <syslog.h> // WWDC 2007 thread-crash workaround 35 36 // 37 // Thread-local storage primitive 38 // 39 ThreadStoreSlot::ThreadStoreSlot(Destructor *destructor) 40 { 41 if (int err = pthread_key_create(&mKey, destructor)) 42 UnixError::throwMe(err); 43 } 44 45 ThreadStoreSlot::~ThreadStoreSlot() 46 { 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); 50 } 51 52 53 // 54 // Mutex implementation 55 // 56 struct MutexAttributes { 57 pthread_mutexattr_t recursive; 58 pthread_mutexattr_t checking; 59 60 MutexAttributes() 61 { 62 pthread_mutexattr_init(&recursive); 63 pthread_mutexattr_settype(&recursive, PTHREAD_MUTEX_RECURSIVE); 64 #if !defined(NDEBUG) 65 pthread_mutexattr_init(&checking); 66 pthread_mutexattr_settype(&checking, PTHREAD_MUTEX_ERRORCHECK); 67 #endif //NDEBUG 68 } 69 }; 70 71 static ModuleNexus<MutexAttributes> mutexAttrs; 72 73 74 Mutex::Mutex() 75 { 76 check(pthread_mutex_init(&me, NULL)); 77 } 78 79 Mutex::Mutex(Type type) 80 { 81 switch (type) { 82 case normal: 83 check(pthread_mutex_init(&me, IFELSEDEBUG(&mutexAttrs().checking, NULL))); 84 break; 85 case recursive: // requested recursive (is also checking, always) 86 check(pthread_mutex_init(&me, &mutexAttrs().recursive)); 87 break; 88 }; 89 } 90 91 92 Mutex::~Mutex() 93 { 94 int result = pthread_mutex_destroy(&me); 95 if(result) { 96 secerror("Probable bug: error destroying Mutex: %d", result); 97 } 98 check(result); 99 } 100 101 102 void Mutex::lock() 103 { 104 check(pthread_mutex_lock(&me)); 105 } 106 107 108 bool Mutex::tryLock() 109 { 110 if (int err = pthread_mutex_trylock(&me)) { 111 if (err != EBUSY) 112 UnixError::throwMe(err); 113 return false; 114 } 115 116 return true; 117 } 118 119 120 void Mutex::unlock() 121 { 122 int result = pthread_mutex_unlock(&me); 123 check(result); 124 } 125 126 127 // 128 // Condition variables 129 // 130 Condition::Condition(Mutex &lock) : mutex(lock) 131 { 132 check(pthread_cond_init(&me, NULL)); 133 } 134 135 Condition::~Condition() 136 { 137 check(pthread_cond_destroy(&me)); 138 } 139 140 void Condition::wait() 141 { 142 check(pthread_cond_wait(&me, &mutex.me)); 143 } 144 145 void Condition::signal() 146 { 147 check(pthread_cond_signal(&me)); 148 } 149 150 void Condition::broadcast() 151 { 152 check(pthread_cond_broadcast(&me)); 153 } 154 155 156 // 157 // CountingMutex implementation. 158 // 159 void CountingMutex::enter() 160 { 161 lock(); 162 mCount++; 163 unlock(); 164 } 165 166 bool CountingMutex::tryEnter() 167 { 168 if (!tryLock()) 169 return false; 170 mCount++; 171 unlock(); 172 return true; 173 } 174 175 void CountingMutex::exit() 176 { 177 lock(); 178 assert(mCount > 0); 179 mCount--; 180 unlock(); 181 } 182 183 void CountingMutex::finishEnter() 184 { 185 mCount++; 186 unlock(); 187 } 188 189 void CountingMutex::finishExit() 190 { 191 assert(mCount > 0); 192 mCount--; 193 unlock(); 194 } 195 196 // 197 // ReadWriteLock implementation 198 // 199 ReadWriteLock::ReadWriteLock() { 200 check(pthread_rwlock_init(&mLock, NULL)); 201 } 202 203 bool ReadWriteLock::lock() { 204 check(pthread_rwlock_rdlock(&mLock)); 205 return true; 206 } 207 208 bool ReadWriteLock::tryLock() { 209 return (pthread_rwlock_tryrdlock(&mLock) == 0); 210 } 211 212 bool ReadWriteLock::writeLock() { 213 check(pthread_rwlock_wrlock(&mLock)); 214 return true; 215 } 216 217 bool ReadWriteLock::tryWriteLock() { 218 return (pthread_rwlock_trywrlock(&mLock) == 0); 219 } 220 221 void ReadWriteLock::unlock() { 222 check(pthread_rwlock_unlock(&mLock)); 223 } 224 225 // 226 // StReadWriteLock implementation 227 // 228 bool StReadWriteLock::lock() { 229 switch(mType) { 230 case Read: mIsLocked = mRWLock.lock(); break; 231 case TryRead: mIsLocked = mRWLock.tryLock(); break; 232 case Write: mIsLocked = mRWLock.writeLock(); break; 233 case TryWrite: mIsLocked = mRWLock.tryWriteLock(); break; 234 } 235 return mIsLocked; 236 } 237 238 void StReadWriteLock::unlock() { 239 mRWLock.unlock(); 240 mIsLocked = false; 241 } 242 243 bool StReadWriteLock::isLocked() { 244 return mIsLocked; 245 } 246 247 248 249 // 250 // Threads implementation 251 // 252 Thread::~Thread() 253 { 254 } 255 256 void Thread::threadRun() 257 { 258 pthread_t pt; 259 pthread_attr_t ptattrs; 260 int err, ntries = 10; // 10 is arbitrary 261 262 if ((err = pthread_attr_init(&ptattrs)) || 263 (err = pthread_attr_setdetachstate(&ptattrs, PTHREAD_CREATE_DETACHED))) 264 { 265 syslog(LOG_ERR, "error %d setting thread detach state", err); 266 } 267 while ((err = pthread_create(&pt, &ptattrs, runner, this) && 268 --ntries)) 269 { 270 syslog(LOG_ERR, "pthread_create() error %d", err); 271 usleep(50000); // 50 ms is arbitrary 272 } 273 if (err) 274 { 275 syslog(LOG_ERR, "too many failed pthread_create() attempts"); 276 } 277 else 278 secinfo("thread", "%p created", pt); 279 } 280 281 void *Thread::runner(void *arg) 282 { 283 try // the top level of any running thread of execution must have a try/catch around it, 284 // otherwise it will crash if something underneath throws. 285 { 286 Thread *me = static_cast<Thread *>(arg); 287 pthread_setname_np(me->threadName); 288 secinfo("thread", "%p: %s starting", pthread_self(), me->threadName); 289 me->threadAction(); 290 secinfo("thread", "%p: %s terminating", pthread_self(), me->threadName); 291 return NULL; 292 } 293 catch (...) 294 { 295 return NULL; 296 } 297 } 298 299 void Thread::threadYield() 300 { 301 ::sched_yield(); 302 }