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//
38ThreadStoreSlot::ThreadStoreSlot(Destructor *destructor)
39{
40    if (int err = pthread_key_create(&mKey, destructor))
41        UnixError::throwMe(err);
42}
43
44ThreadStoreSlot::~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//
55struct 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
70static ModuleNexus<MutexAttributes> mutexAttrs;
71
72
73Mutex::Mutex()
74{
75	check(pthread_mutex_init(&me, NULL));
76}
77
78Mutex::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
91Mutex::~Mutex()
92{
93    int result = pthread_mutex_destroy(&me);
94	check(result);
95}
96
97
98void Mutex::lock()
99{
100	check(pthread_mutex_lock(&me));
101}
102
103
104bool 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
116void Mutex::unlock()
117{
118    int result = pthread_mutex_unlock(&me);
119	check(result);
120}
121
122
123//
124// Condition variables
125//
126Condition::Condition(Mutex &lock) : mutex(lock)
127{
128    check(pthread_cond_init(&me, NULL));
129}
130
131Condition::~Condition()
132{
133	check(pthread_cond_destroy(&me));
134}
135
136void Condition::wait()
137{
138    check(pthread_cond_wait(&me, &mutex.me));
139}
140
141void Condition::signal()
142{
143    check(pthread_cond_signal(&me));
144}
145
146void Condition::broadcast()
147{
148    check(pthread_cond_broadcast(&me));
149}
150
151
152//
153// CountingMutex implementation.
154//
155void CountingMutex::enter()
156{
157    lock();
158    mCount++;
159    secdebug("cmutex", "%p up to %d", this, mCount);
160    unlock();
161}
162
163bool 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
173void CountingMutex::exit()
174{
175    lock();
176    assert(mCount > 0);
177    mCount--;
178    secdebug("cmutex", "%p down to %d", this, mCount);
179    unlock();
180}
181
182void CountingMutex::finishEnter()
183{
184    mCount++;
185    secdebug("cmutex", "%p finish up to %d", this, mCount);
186    unlock();
187}
188
189void 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
199//
200// Threads implementation
201//
202Thread::~Thread()
203{
204}
205
206void Thread::run()
207{
208    pthread_attr_t ptattrs;
209    int err, ntries = 10;       // 10 is arbitrary
210
211    if ((err = pthread_attr_init(&ptattrs)) ||
212        (err = pthread_attr_setdetachstate(&ptattrs, PTHREAD_CREATE_DETACHED)))
213    {
214        syslog(LOG_ERR, "error %d setting thread detach state", err);
215    }
216    while ((err = pthread_create(&self.mIdent, &ptattrs, runner, this) &&
217           --ntries))
218    {
219        syslog(LOG_ERR, "pthread_create() error %d", err);
220        usleep(50000);          // 50 ms is arbitrary
221    }
222    if (err)
223    {
224        syslog(LOG_ERR, "too many failed pthread_create() attempts");
225    }
226    else
227        secdebug("thread", "%p created", self.mIdent);
228}
229
230void *Thread::runner(void *arg)
231{
232    try // the top level of any running thread of execution must have a try/catch around it,
233        // otherwise it will crash if something underneath throws.
234    {
235        Thread *me = static_cast<Thread *>(arg);
236        secdebug("thread", "%p starting", me->self.mIdent);
237        me->action();
238        secdebug("thread", "%p terminating", me->self.mIdent);
239        delete me;
240        return NULL;
241    }
242    catch (...)
243    {
244        return NULL;
245    }
246}
247
248void Thread::yield()
249{
250	::sched_yield();
251}
252
253
254//
255// ThreadRunner implementation
256//
257ThreadRunner::ThreadRunner(Action *todo)
258{
259    mAction = todo;
260    run();
261}
262
263void ThreadRunner::action()
264{
265    mAction();
266}
267