]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_utilities/lib/threading.cpp
Security-57337.40.85.tar.gz
[apple/security.git] / OSX / libsecurity_utilities / lib / 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
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 //
38 ThreadStoreSlot::ThreadStoreSlot(Destructor *destructor)
39 {
40 if (int err = pthread_key_create(&mKey, destructor))
41 UnixError::throwMe(err);
42 }
43
44 ThreadStoreSlot::~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 //
55 struct 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
70 static ModuleNexus<MutexAttributes> mutexAttrs;
71
72
73 Mutex::Mutex()
74 {
75 check(pthread_mutex_init(&me, NULL));
76 }
77
78 Mutex::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
91 Mutex::~Mutex()
92 {
93 int result = pthread_mutex_destroy(&me);
94 check(result);
95 }
96
97
98 void Mutex::lock()
99 {
100 check(pthread_mutex_lock(&me));
101 }
102
103
104 bool 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
116 void Mutex::unlock()
117 {
118 int result = pthread_mutex_unlock(&me);
119 check(result);
120 }
121
122
123 //
124 // Condition variables
125 //
126 Condition::Condition(Mutex &lock) : mutex(lock)
127 {
128 check(pthread_cond_init(&me, NULL));
129 }
130
131 Condition::~Condition()
132 {
133 check(pthread_cond_destroy(&me));
134 }
135
136 void Condition::wait()
137 {
138 check(pthread_cond_wait(&me, &mutex.me));
139 }
140
141 void Condition::signal()
142 {
143 check(pthread_cond_signal(&me));
144 }
145
146 void Condition::broadcast()
147 {
148 check(pthread_cond_broadcast(&me));
149 }
150
151
152 //
153 // CountingMutex implementation.
154 //
155 void CountingMutex::enter()
156 {
157 lock();
158 mCount++;
159 secdebug("cmutex", "%p up to %d", this, mCount);
160 unlock();
161 }
162
163 bool 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
173 void CountingMutex::exit()
174 {
175 lock();
176 assert(mCount > 0);
177 mCount--;
178 secdebug("cmutex", "%p down to %d", this, mCount);
179 unlock();
180 }
181
182 void CountingMutex::finishEnter()
183 {
184 mCount++;
185 secdebug("cmutex", "%p finish up to %d", this, mCount);
186 unlock();
187 }
188
189 void 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 // ReadWriteLock implementation
199 //
200 ReadWriteLock::ReadWriteLock() {
201 check(pthread_rwlock_init(&mLock, NULL));
202 }
203
204 bool ReadWriteLock::lock() {
205 check(pthread_rwlock_rdlock(&mLock));
206 return true;
207 }
208
209 bool ReadWriteLock::tryLock() {
210 return (pthread_rwlock_tryrdlock(&mLock) == 0);
211 }
212
213 bool ReadWriteLock::writeLock() {
214 check(pthread_rwlock_wrlock(&mLock));
215 return true;
216 }
217
218 bool ReadWriteLock::tryWriteLock() {
219 return (pthread_rwlock_trywrlock(&mLock) == 0);
220 }
221
222 void ReadWriteLock::unlock() {
223 check(pthread_rwlock_unlock(&mLock));
224 }
225
226 //
227 // StReadWriteLock implementation
228 //
229 bool StReadWriteLock::lock() {
230 switch(mType) {
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;
235 }
236 return mIsLocked;
237 }
238
239 void StReadWriteLock::unlock() {
240 mRWLock.unlock();
241 mIsLocked = false;
242 }
243
244 bool StReadWriteLock::isLocked() {
245 return mIsLocked;
246 }
247
248
249
250 //
251 // Threads implementation
252 //
253 Thread::~Thread()
254 {
255 }
256
257 void Thread::run()
258 {
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(&self.mIdent, &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 secdebug("thread", "%p created", self.mIdent);
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 secdebug("thread", "%p starting", me->self.mIdent);
288 me->action();
289 secdebug("thread", "%p terminating", me->self.mIdent);
290 delete me;
291 return NULL;
292 }
293 catch (...)
294 {
295 return NULL;
296 }
297 }
298
299 void Thread::yield()
300 {
301 ::sched_yield();
302 }
303
304
305 //
306 // ThreadRunner implementation
307 //
308 ThreadRunner::ThreadRunner(Action *todo)
309 {
310 mAction = todo;
311 run();
312 }
313
314 void ThreadRunner::action()
315 {
316 mAction();
317 }