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>
31 #include <utilities/debugging.h>
33 #include <unistd.h> // WWDC 2007 thread-crash workaround
34 #include <syslog.h> // WWDC 2007 thread-crash workaround
37 // Thread-local storage primitive
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
);
54 // Mutex implementation
56 struct MutexAttributes
{
57 pthread_mutexattr_t recursive
;
58 pthread_mutexattr_t checking
;
62 pthread_mutexattr_init(&recursive
);
63 pthread_mutexattr_settype(&recursive
, PTHREAD_MUTEX_RECURSIVE
);
65 pthread_mutexattr_init(&checking
);
66 pthread_mutexattr_settype(&checking
, PTHREAD_MUTEX_ERRORCHECK
);
71 static ModuleNexus
<MutexAttributes
> mutexAttrs
;
76 check(pthread_mutex_init(&me
, NULL
));
79 Mutex::Mutex(Type type
)
83 check(pthread_mutex_init(&me
, IFELSEDEBUG(&mutexAttrs().checking
, NULL
)));
85 case recursive
: // requested recursive (is also checking, always)
86 check(pthread_mutex_init(&me
, &mutexAttrs().recursive
));
94 int result
= pthread_mutex_destroy(&me
);
96 secerror("Probable bug: error destroying Mutex: %d", result
);
104 check(pthread_mutex_lock(&me
));
108 bool Mutex::tryLock()
110 if (int err
= pthread_mutex_trylock(&me
)) {
112 UnixError::throwMe(err
);
122 int result
= pthread_mutex_unlock(&me
);
128 // Condition variables
130 Condition::Condition(Mutex
&lock
) : mutex(lock
)
132 check(pthread_cond_init(&me
, NULL
));
135 Condition::~Condition()
137 check(pthread_cond_destroy(&me
));
140 void Condition::wait()
142 check(pthread_cond_wait(&me
, &mutex
.me
));
145 void Condition::signal()
147 check(pthread_cond_signal(&me
));
150 void Condition::broadcast()
152 check(pthread_cond_broadcast(&me
));
157 // CountingMutex implementation.
159 void CountingMutex::enter()
166 bool CountingMutex::tryEnter()
175 void CountingMutex::exit()
183 void CountingMutex::finishEnter()
189 void CountingMutex::finishExit()
197 // ReadWriteLock implementation
199 ReadWriteLock::ReadWriteLock() {
200 check(pthread_rwlock_init(&mLock
, NULL
));
203 bool ReadWriteLock::lock() {
204 check(pthread_rwlock_rdlock(&mLock
));
208 bool ReadWriteLock::tryLock() {
209 return (pthread_rwlock_tryrdlock(&mLock
) == 0);
212 bool ReadWriteLock::writeLock() {
213 check(pthread_rwlock_wrlock(&mLock
));
217 bool ReadWriteLock::tryWriteLock() {
218 return (pthread_rwlock_trywrlock(&mLock
) == 0);
221 void ReadWriteLock::unlock() {
222 check(pthread_rwlock_unlock(&mLock
));
226 // StReadWriteLock implementation
228 bool StReadWriteLock::lock() {
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;
238 void StReadWriteLock::unlock() {
243 bool StReadWriteLock::isLocked() {
250 // 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(&pt
, &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 secinfo("thread", "%p created", pt
);
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 secinfo("thread", "%p starting", pthread_self());
289 secinfo("thread", "%p terminating", pthread_self());
306 // ThreadRunner implementation
308 ThreadRunner::ThreadRunner(Action
*todo
)
314 void ThreadRunner::action()