1 /*
2 * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
4 * Copyright (C) 2011 Research In Motion Limited. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
16 * its contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32 #include "wtf/Threading.h"
33
34 #if USE(PTHREADS)
35
36 #include "wtf/DateMath.h"
37 #include "wtf/HashMap.h"
38 #include "wtf/OwnPtr.h"
39 #include "wtf/PassOwnPtr.h"
40 #include "wtf/StdLibExtras.h"
41 #include "wtf/ThreadFunctionInvocation.h"
42 #include "wtf/ThreadIdentifierDataPthreads.h"
43 #include "wtf/ThreadSpecific.h"
44 #include "wtf/ThreadingPrimitives.h"
45 #include "wtf/WTFThreadData.h"
46 #include "wtf/dtoa.h"
47 #include "wtf/dtoa/cached-powers.h"
48 #include <errno.h>
49
50 #if !COMPILER(MSVC)
51 #include <limits.h>
52 #include <sched.h>
53 #include <sys/time.h>
54 #endif
55
56 #if OS(MACOSX)
57 #include <objc/objc-auto.h>
58 #endif
59
60 namespace WTF {
61
62 class PthreadState {
63 WTF_MAKE_FAST_ALLOCATED;
64 public:
65 enum JoinableState {
66 Joinable, // The default thread state. The thread can be joined on.
67
68 Joined, // Somebody waited on this thread to exit and this thread finally exited. This state is here because there can be a
69 // period of time between when the thread exits (which causes pthread_join to return and the remainder of waitOnThreadCompletion to run)
70 // and when threadDidExit is called. We need threadDidExit to take charge and delete the thread data since there's
71 // nobody else to pick up the slack in this case (since waitOnThreadCompletion has already returned).
72
73 Detached // The thread has been detached and can no longer be joined on. At this point, the thread must take care of cleaning up after itself.
74 };
75
76 // Currently all threads created by WTF start out as joinable.
PthreadState(pthread_t handle)77 PthreadState(pthread_t handle)
78 : m_joinableState(Joinable)
79 , m_didExit(false)
80 , m_pthreadHandle(handle)
81 {
82 }
83
joinableState()84 JoinableState joinableState() { return m_joinableState; }
pthreadHandle()85 pthread_t pthreadHandle() { return m_pthreadHandle; }
didBecomeDetached()86 void didBecomeDetached() { m_joinableState = Detached; }
didExit()87 void didExit() { m_didExit = true; }
didJoin()88 void didJoin() { m_joinableState = Joined; }
hasExited()89 bool hasExited() { return m_didExit; }
90
91 private:
92 JoinableState m_joinableState;
93 bool m_didExit;
94 pthread_t m_pthreadHandle;
95 };
96
97 typedef HashMap<ThreadIdentifier, OwnPtr<PthreadState> > ThreadMap;
98
99 static Mutex* atomicallyInitializedStaticMutex;
100
101 void unsafeThreadWasDetached(ThreadIdentifier);
102 void threadDidExit(ThreadIdentifier);
103 void threadWasJoined(ThreadIdentifier);
104
threadMapMutex()105 static Mutex& threadMapMutex()
106 {
107 DEFINE_STATIC_LOCAL(Mutex, mutex, ());
108 return mutex;
109 }
110
initializeThreading()111 void initializeThreading()
112 {
113 // This should only be called once.
114 ASSERT(!atomicallyInitializedStaticMutex);
115
116 // StringImpl::empty() does not construct its static string in a threadsafe fashion,
117 // so ensure it has been initialized from here.
118 StringImpl::empty();
119 atomicallyInitializedStaticMutex = new Mutex;
120 threadMapMutex();
121 ThreadIdentifierData::initializeOnce();
122 wtfThreadData();
123 s_dtoaP5Mutex = new Mutex;
124 initializeDates();
125 }
126
lockAtomicallyInitializedStaticMutex()127 void lockAtomicallyInitializedStaticMutex()
128 {
129 ASSERT(atomicallyInitializedStaticMutex);
130 atomicallyInitializedStaticMutex->lock();
131 }
132
unlockAtomicallyInitializedStaticMutex()133 void unlockAtomicallyInitializedStaticMutex()
134 {
135 atomicallyInitializedStaticMutex->unlock();
136 }
137
threadMap()138 static ThreadMap& threadMap()
139 {
140 DEFINE_STATIC_LOCAL(ThreadMap, map, ());
141 return map;
142 }
143
identifierByPthreadHandle(const pthread_t & pthreadHandle)144 static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle)
145 {
146 MutexLocker locker(threadMapMutex());
147
148 ThreadMap::iterator i = threadMap().begin();
149 for (; i != threadMap().end(); ++i) {
150 if (pthread_equal(i->value->pthreadHandle(), pthreadHandle) && !i->value->hasExited())
151 return i->key;
152 }
153
154 return 0;
155 }
156
establishIdentifierForPthreadHandle(const pthread_t & pthreadHandle)157 static ThreadIdentifier establishIdentifierForPthreadHandle(const pthread_t& pthreadHandle)
158 {
159 ASSERT(!identifierByPthreadHandle(pthreadHandle));
160 MutexLocker locker(threadMapMutex());
161 static ThreadIdentifier identifierCount = 1;
162 threadMap().add(identifierCount, adoptPtr(new PthreadState(pthreadHandle)));
163 return identifierCount++;
164 }
165
pthreadHandleForIdentifierWithLockAlreadyHeld(ThreadIdentifier id)166 static pthread_t pthreadHandleForIdentifierWithLockAlreadyHeld(ThreadIdentifier id)
167 {
168 return threadMap().get(id)->pthreadHandle();
169 }
170
wtfThreadEntryPoint(void * param)171 static void* wtfThreadEntryPoint(void* param)
172 {
173 // Balanced by .leakPtr() in createThreadInternal.
174 OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(static_cast<ThreadFunctionInvocation*>(param));
175 invocation->function(invocation->data);
176 return 0;
177 }
178
createThreadInternal(ThreadFunction entryPoint,void * data,const char *)179 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
180 {
181 OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(new ThreadFunctionInvocation(entryPoint, data));
182 pthread_t threadHandle;
183 if (pthread_create(&threadHandle, 0, wtfThreadEntryPoint, invocation.get())) {
184 WTF_LOG_ERROR("Failed to create pthread at entry point %p with data %p", wtfThreadEntryPoint, invocation.get());
185 return 0;
186 }
187
188 // Balanced by adoptPtr() in wtfThreadEntryPoint.
189 ThreadFunctionInvocation* leakedInvocation ALLOW_UNUSED = invocation.leakPtr();
190
191 return establishIdentifierForPthreadHandle(threadHandle);
192 }
193
initializeCurrentThreadInternal(const char * threadName)194 void initializeCurrentThreadInternal(const char* threadName)
195 {
196 #if HAVE(PTHREAD_SETNAME_NP)
197 pthread_setname_np(threadName);
198 #endif
199
200 #if OS(MACOSX)
201 // All threads that potentially use APIs above the BSD layer must be registered with the Objective-C
202 // garbage collector in case API implementations use garbage-collected memory.
203 objc_registerThreadWithCollector();
204 #endif
205
206 ThreadIdentifier id = identifierByPthreadHandle(pthread_self());
207 ASSERT(id);
208 ThreadIdentifierData::initialize(id);
209 }
210
waitForThreadCompletion(ThreadIdentifier threadID)211 int waitForThreadCompletion(ThreadIdentifier threadID)
212 {
213 pthread_t pthreadHandle;
214 ASSERT(threadID);
215
216 {
217 // We don't want to lock across the call to join, since that can block our thread and cause deadlock.
218 MutexLocker locker(threadMapMutex());
219 pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID);
220 ASSERT(pthreadHandle);
221 }
222
223 int joinResult = pthread_join(pthreadHandle, 0);
224
225 if (joinResult == EDEADLK)
226 WTF_LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
227 else if (joinResult)
228 WTF_LOG_ERROR("ThreadIdentifier %u was unable to be joined.\n", threadID);
229
230 MutexLocker locker(threadMapMutex());
231 PthreadState* state = threadMap().get(threadID);
232 ASSERT(state);
233 ASSERT(state->joinableState() == PthreadState::Joinable);
234
235 // The thread has already exited, so clean up after it.
236 if (state->hasExited())
237 threadMap().remove(threadID);
238 // The thread hasn't exited yet, so don't clean anything up. Just signal that we've already joined on it so that it will clean up after itself.
239 else
240 state->didJoin();
241
242 return joinResult;
243 }
244
detachThread(ThreadIdentifier threadID)245 void detachThread(ThreadIdentifier threadID)
246 {
247 ASSERT(threadID);
248
249 MutexLocker locker(threadMapMutex());
250 pthread_t pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID);
251 ASSERT(pthreadHandle);
252
253 int detachResult = pthread_detach(pthreadHandle);
254 if (detachResult)
255 WTF_LOG_ERROR("ThreadIdentifier %u was unable to be detached\n", threadID);
256
257 PthreadState* state = threadMap().get(threadID);
258 ASSERT(state);
259 if (state->hasExited())
260 threadMap().remove(threadID);
261 else
262 threadMap().get(threadID)->didBecomeDetached();
263 }
264
threadDidExit(ThreadIdentifier threadID)265 void threadDidExit(ThreadIdentifier threadID)
266 {
267 MutexLocker locker(threadMapMutex());
268 PthreadState* state = threadMap().get(threadID);
269 ASSERT(state);
270
271 state->didExit();
272
273 if (state->joinableState() != PthreadState::Joinable)
274 threadMap().remove(threadID);
275 }
276
yield()277 void yield()
278 {
279 sched_yield();
280 }
281
currentThread()282 ThreadIdentifier currentThread()
283 {
284 ThreadIdentifier id = ThreadIdentifierData::identifier();
285 if (id)
286 return id;
287
288 // Not a WTF-created thread, ThreadIdentifier is not established yet.
289 id = establishIdentifierForPthreadHandle(pthread_self());
290 ThreadIdentifierData::initialize(id);
291 return id;
292 }
293
Mutex()294 Mutex::Mutex()
295 {
296 pthread_mutexattr_t attr;
297 pthread_mutexattr_init(&attr);
298 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
299
300 int result = pthread_mutex_init(&m_mutex, &attr);
301 ASSERT_UNUSED(result, !result);
302
303 pthread_mutexattr_destroy(&attr);
304 }
305
~Mutex()306 Mutex::~Mutex()
307 {
308 int result = pthread_mutex_destroy(&m_mutex);
309 ASSERT_UNUSED(result, !result);
310 }
311
lock()312 void Mutex::lock()
313 {
314 int result = pthread_mutex_lock(&m_mutex);
315 ASSERT_UNUSED(result, !result);
316 }
317
tryLock()318 bool Mutex::tryLock()
319 {
320 int result = pthread_mutex_trylock(&m_mutex);
321
322 if (result == 0)
323 return true;
324 if (result == EBUSY)
325 return false;
326
327 ASSERT_NOT_REACHED();
328 return false;
329 }
330
unlock()331 void Mutex::unlock()
332 {
333 int result = pthread_mutex_unlock(&m_mutex);
334 ASSERT_UNUSED(result, !result);
335 }
336
ThreadCondition()337 ThreadCondition::ThreadCondition()
338 {
339 pthread_cond_init(&m_condition, NULL);
340 }
341
~ThreadCondition()342 ThreadCondition::~ThreadCondition()
343 {
344 pthread_cond_destroy(&m_condition);
345 }
346
wait(Mutex & mutex)347 void ThreadCondition::wait(Mutex& mutex)
348 {
349 int result = pthread_cond_wait(&m_condition, &mutex.impl());
350 ASSERT_UNUSED(result, !result);
351 }
352
timedWait(Mutex & mutex,double absoluteTime)353 bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
354 {
355 if (absoluteTime < currentTime())
356 return false;
357
358 if (absoluteTime > INT_MAX) {
359 wait(mutex);
360 return true;
361 }
362
363 int timeSeconds = static_cast<int>(absoluteTime);
364 int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9);
365
366 timespec targetTime;
367 targetTime.tv_sec = timeSeconds;
368 targetTime.tv_nsec = timeNanoseconds;
369
370 return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0;
371 }
372
signal()373 void ThreadCondition::signal()
374 {
375 int result = pthread_cond_signal(&m_condition);
376 ASSERT_UNUSED(result, !result);
377 }
378
broadcast()379 void ThreadCondition::broadcast()
380 {
381 int result = pthread_cond_broadcast(&m_condition);
382 ASSERT_UNUSED(result, !result);
383 }
384
385 } // namespace WTF
386
387 #endif // USE(PTHREADS)
388