]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_utilities/lib/threading.cpp
Security-57740.31.2.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 #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::run()
257 {
258 pthread_attr_t ptattrs;
259 int err, ntries = 10; // 10 is arbitrary
260
261 if ((err = pthread_attr_init(&ptattrs)) ||
262 (err = pthread_attr_setdetachstate(&ptattrs, PTHREAD_CREATE_DETACHED)))
263 {
264 syslog(LOG_ERR, "error %d setting thread detach state", err);
265 }
266 while ((err = pthread_create(&self.mIdent, &ptattrs, runner, this) &&
267 --ntries))
268 {
269 syslog(LOG_ERR, "pthread_create() error %d", err);
270 usleep(50000); // 50 ms is arbitrary
271 }
272 if (err)
273 {
274 syslog(LOG_ERR, "too many failed pthread_create() attempts");
275 }
276 else
277 secinfo("thread", "%p created", self.mIdent);
278 }
279
280 void *Thread::runner(void *arg)
281 {
282 try // the top level of any running thread of execution must have a try/catch around it,
283 // otherwise it will crash if something underneath throws.
284 {
285 Thread *me = static_cast<Thread *>(arg);
286 secinfo("thread", "%p starting", me->self.mIdent);
287 me->action();
288 secinfo("thread", "%p terminating", me->self.mIdent);
289 delete me;
290 return NULL;
291 }
292 catch (...)
293 {
294 return NULL;
295 }
296 }
297
298 void Thread::yield()
299 {
300 ::sched_yield();
301 }
302
303
304 //
305 // ThreadRunner implementation
306 //
307 ThreadRunner::ThreadRunner(Action *todo)
308 {
309 mAction = todo;
310 run();
311 }
312
313 void ThreadRunner::action()
314 {
315 mAction();
316 }