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.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
32 #include "wtf/Threading.h"
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"
47 #include "wtf/dtoa/cached-powers.h"
57 #include <objc/objc-auto.h>
63 WTF_MAKE_FAST_ALLOCATED;
66 Joinable, // The default thread state. The thread can be joined on.
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).
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.
76 // Currently all threads created by WTF start out as joinable.
77 PthreadState(pthread_t handle)
78 : m_joinableState(Joinable)
80 , m_pthreadHandle(handle)
84 JoinableState joinableState() { return m_joinableState; }
85 pthread_t pthreadHandle() { return m_pthreadHandle; }
86 void didBecomeDetached() { m_joinableState = Detached; }
87 void didExit() { m_didExit = true; }
88 void didJoin() { m_joinableState = Joined; }
89 bool hasExited() { return m_didExit; }
92 JoinableState m_joinableState;
94 pthread_t m_pthreadHandle;
97 typedef HashMap<ThreadIdentifier, OwnPtr<PthreadState> > ThreadMap;
99 static Mutex* atomicallyInitializedStaticMutex;
101 void unsafeThreadWasDetached(ThreadIdentifier);
102 void threadDidExit(ThreadIdentifier);
103 void threadWasJoined(ThreadIdentifier);
105 static Mutex& threadMapMutex()
107 DEFINE_STATIC_LOCAL(Mutex, mutex, ());
111 void initializeThreading()
113 // This should only be called once.
114 ASSERT(!atomicallyInitializedStaticMutex);
116 // StringImpl::empty() does not construct its static string in a threadsafe fashion,
117 // so ensure it has been initialized from here.
119 atomicallyInitializedStaticMutex = new Mutex;
121 ThreadIdentifierData::initializeOnce();
123 s_dtoaP5Mutex = new Mutex;
127 void lockAtomicallyInitializedStaticMutex()
129 ASSERT(atomicallyInitializedStaticMutex);
130 atomicallyInitializedStaticMutex->lock();
133 void unlockAtomicallyInitializedStaticMutex()
135 atomicallyInitializedStaticMutex->unlock();
138 static ThreadMap& threadMap()
140 DEFINE_STATIC_LOCAL(ThreadMap, map, ());
144 static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle)
146 MutexLocker locker(threadMapMutex());
148 ThreadMap::iterator i = threadMap().begin();
149 for (; i != threadMap().end(); ++i) {
150 if (pthread_equal(i->value->pthreadHandle(), pthreadHandle) && !i->value->hasExited())
157 static ThreadIdentifier establishIdentifierForPthreadHandle(const pthread_t& pthreadHandle)
159 ASSERT(!identifierByPthreadHandle(pthreadHandle));
160 MutexLocker locker(threadMapMutex());
161 static ThreadIdentifier identifierCount = 1;
162 threadMap().add(identifierCount, adoptPtr(new PthreadState(pthreadHandle)));
163 return identifierCount++;
166 static pthread_t pthreadHandleForIdentifierWithLockAlreadyHeld(ThreadIdentifier id)
168 return threadMap().get(id)->pthreadHandle();
171 static void* wtfThreadEntryPoint(void* param)
173 // Balanced by .leakPtr() in createThreadInternal.
174 OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(static_cast<ThreadFunctionInvocation*>(param));
175 invocation->function(invocation->data);
179 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
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());
188 // Balanced by adoptPtr() in wtfThreadEntryPoint.
189 ThreadFunctionInvocation* leakedInvocation ALLOW_UNUSED = invocation.leakPtr();
191 return establishIdentifierForPthreadHandle(threadHandle);
194 void initializeCurrentThreadInternal(const char* threadName)
196 #if HAVE(PTHREAD_SETNAME_NP)
197 pthread_setname_np(threadName);
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();
206 ThreadIdentifier id = identifierByPthreadHandle(pthread_self());
208 ThreadIdentifierData::initialize(id);
211 int waitForThreadCompletion(ThreadIdentifier threadID)
213 pthread_t pthreadHandle;
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);
223 int joinResult = pthread_join(pthreadHandle, 0);
225 if (joinResult == EDEADLK)
226 WTF_LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
228 WTF_LOG_ERROR("ThreadIdentifier %u was unable to be joined.\n", threadID);
230 MutexLocker locker(threadMapMutex());
231 PthreadState* state = threadMap().get(threadID);
233 ASSERT(state->joinableState() == PthreadState::Joinable);
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.
245 void detachThread(ThreadIdentifier threadID)
249 MutexLocker locker(threadMapMutex());
250 pthread_t pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID);
251 ASSERT(pthreadHandle);
253 int detachResult = pthread_detach(pthreadHandle);
255 WTF_LOG_ERROR("ThreadIdentifier %u was unable to be detached\n", threadID);
257 PthreadState* state = threadMap().get(threadID);
259 if (state->hasExited())
260 threadMap().remove(threadID);
262 threadMap().get(threadID)->didBecomeDetached();
265 void threadDidExit(ThreadIdentifier threadID)
267 MutexLocker locker(threadMapMutex());
268 PthreadState* state = threadMap().get(threadID);
273 if (state->joinableState() != PthreadState::Joinable)
274 threadMap().remove(threadID);
282 ThreadIdentifier currentThread()
284 ThreadIdentifier id = ThreadIdentifierData::identifier();
288 // Not a WTF-created thread, ThreadIdentifier is not established yet.
289 id = establishIdentifierForPthreadHandle(pthread_self());
290 ThreadIdentifierData::initialize(id);
296 pthread_mutexattr_t attr;
297 pthread_mutexattr_init(&attr);
298 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
300 int result = pthread_mutex_init(&m_mutex, &attr);
301 ASSERT_UNUSED(result, !result);
303 pthread_mutexattr_destroy(&attr);
308 int result = pthread_mutex_destroy(&m_mutex);
309 ASSERT_UNUSED(result, !result);
314 int result = pthread_mutex_lock(&m_mutex);
315 ASSERT_UNUSED(result, !result);
318 bool Mutex::tryLock()
320 int result = pthread_mutex_trylock(&m_mutex);
327 ASSERT_NOT_REACHED();
333 int result = pthread_mutex_unlock(&m_mutex);
334 ASSERT_UNUSED(result, !result);
337 ThreadCondition::ThreadCondition()
339 pthread_cond_init(&m_condition, NULL);
342 ThreadCondition::~ThreadCondition()
344 pthread_cond_destroy(&m_condition);
347 void ThreadCondition::wait(Mutex& mutex)
349 int result = pthread_cond_wait(&m_condition, &mutex.impl());
350 ASSERT_UNUSED(result, !result);
353 bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
355 if (absoluteTime < currentTime())
358 if (absoluteTime > INT_MAX) {
363 int timeSeconds = static_cast<int>(absoluteTime);
364 int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9);
367 targetTime.tv_sec = timeSeconds;
368 targetTime.tv_nsec = timeNanoseconds;
370 return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0;
373 void ThreadCondition::signal()
375 int result = pthread_cond_signal(&m_condition);
376 ASSERT_UNUSED(result, !result);
379 void ThreadCondition::broadcast()
381 int result = pthread_cond_broadcast(&m_condition);
382 ASSERT_UNUSED(result, !result);
387 #endif // USE(PTHREADS)