2 * Copyright (c) 2000-2004,2011-2012,2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 // threading - generic thread support
28 #include <security_utilities/threading.h>
29 #include <security_utilities/globalizer.h>
30 #include <security_utilities/memutils.h>
32 #include <unistd.h> // WWDC 2007 thread-crash workaround
33 #include <syslog.h> // WWDC 2007 thread-crash workaround
36 // Thread-local storage primitive
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
);
53 // Mutex implementation
55 struct MutexAttributes
{
56 pthread_mutexattr_t recursive
;
57 pthread_mutexattr_t checking
;
61 pthread_mutexattr_init(&recursive
);
62 pthread_mutexattr_settype(&recursive
, PTHREAD_MUTEX_RECURSIVE
);
64 pthread_mutexattr_init(&checking
);
65 pthread_mutexattr_settype(&checking
, PTHREAD_MUTEX_ERRORCHECK
);
70 static ModuleNexus
<MutexAttributes
> mutexAttrs
;
75 check(pthread_mutex_init(&me
, NULL
));
78 Mutex::Mutex(Type type
)
82 check(pthread_mutex_init(&me
, IFELSEDEBUG(&mutexAttrs().checking
, NULL
)));
84 case recursive
: // requested recursive (is also checking, always)
85 check(pthread_mutex_init(&me
, &mutexAttrs().recursive
));
93 int result
= pthread_mutex_destroy(&me
);
100 check(pthread_mutex_lock(&me
));
104 bool Mutex::tryLock()
106 if (int err
= pthread_mutex_trylock(&me
)) {
108 UnixError::throwMe(err
);
118 int result
= pthread_mutex_unlock(&me
);
124 // Condition variables
126 Condition::Condition(Mutex
&lock
) : mutex(lock
)
128 check(pthread_cond_init(&me
, NULL
));
131 Condition::~Condition()
133 check(pthread_cond_destroy(&me
));
136 void Condition::wait()
138 check(pthread_cond_wait(&me
, &mutex
.me
));
141 void Condition::signal()
143 check(pthread_cond_signal(&me
));
146 void Condition::broadcast()
148 check(pthread_cond_broadcast(&me
));
153 // CountingMutex implementation.
155 void CountingMutex::enter()
159 secdebug("cmutex", "%p up to %d", this, mCount
);
163 bool CountingMutex::tryEnter()
168 secdebug("cmutex", "%p up to %d (was try)", this, mCount
);
173 void CountingMutex::exit()
178 secdebug("cmutex", "%p down to %d", this, mCount
);
182 void CountingMutex::finishEnter()
185 secdebug("cmutex", "%p finish up to %d", this, mCount
);
189 void CountingMutex::finishExit()
193 secdebug("cmutex", "%p finish down to %d", this, mCount
);
198 // ReadWriteLock implementation
200 ReadWriteLock::ReadWriteLock() {
201 check(pthread_rwlock_init(&mLock
, NULL
));
204 bool ReadWriteLock::lock() {
205 check(pthread_rwlock_rdlock(&mLock
));
209 bool ReadWriteLock::tryLock() {
210 return (pthread_rwlock_tryrdlock(&mLock
) == 0);
213 bool ReadWriteLock::writeLock() {
214 check(pthread_rwlock_wrlock(&mLock
));
218 bool ReadWriteLock::tryWriteLock() {
219 return (pthread_rwlock_trywrlock(&mLock
) == 0);
222 void ReadWriteLock::unlock() {
223 check(pthread_rwlock_unlock(&mLock
));
227 // StReadWriteLock implementation
229 bool StReadWriteLock::lock() {
231 case Read
: mIsLocked
= mRWLock
.lock(); break;
232 case TryRead
: mIsLocked
= mRWLock
.tryLock(); break;
233 case Write
: mIsLocked
= mRWLock
.writeLock(); break;
234 case TryWrite
: mIsLocked
= mRWLock
.tryWriteLock(); break;
239 void StReadWriteLock::unlock() {
244 bool StReadWriteLock::isLocked() {
251 // Threads implementation
259 pthread_attr_t ptattrs
;
260 int err
, ntries
= 10; // 10 is arbitrary
262 if ((err
= pthread_attr_init(&ptattrs
)) ||
263 (err
= pthread_attr_setdetachstate(&ptattrs
, PTHREAD_CREATE_DETACHED
)))
265 syslog(LOG_ERR
, "error %d setting thread detach state", err
);
267 while ((err
= pthread_create(&self
.mIdent
, &ptattrs
, runner
, this) &&
270 syslog(LOG_ERR
, "pthread_create() error %d", err
);
271 usleep(50000); // 50 ms is arbitrary
275 syslog(LOG_ERR
, "too many failed pthread_create() attempts");
278 secdebug("thread", "%p created", self
.mIdent
);
281 void *Thread::runner(void *arg
)
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.
286 Thread
*me
= static_cast<Thread
*>(arg
);
287 secdebug("thread", "%p starting", me
->self
.mIdent
);
289 secdebug("thread", "%p terminating", me
->self
.mIdent
);
306 // ThreadRunner implementation
308 ThreadRunner::ThreadRunner(Action
*todo
)
314 void ThreadRunner::action()