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 "Threading.h"
36 #include "CurrentTime.h"
39 #include "dtoa/cached-powers.h"
41 #include "RandomNumberSeed.h"
42 #include "StdLibExtras.h"
43 #include "ThreadFunctionInvocation.h"
44 #include "ThreadIdentifierDataPthreads.h"
45 #include "ThreadSpecific.h"
46 #include "UnusedParam.h"
47 #include <wtf/OwnPtr.h>
48 #include <wtf/PassOwnPtr.h>
49 #include <wtf/WTFThreadData.h>
58 #if OS(MAC_OS_X) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
59 #include <objc/objc-auto.h>
67 Joinable, // The default thread state. The thread can be joined on.
69 Joined, // Somebody waited on this thread to exit and this thread finally exited. This state is here because there can be a
70 // period of time between when the thread exits (which causes pthread_join to return and the remainder of waitOnThreadCompletion to run)
71 // and when threadDidExit is called. We need threadDidExit to take charge and delete the thread data since there's
72 // nobody else to pick up the slack in this case (since waitOnThreadCompletion has already returned).
74 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.
77 // Currently all threads created by WTF start out as joinable.
78 PthreadState(pthread_t handle)
79 : m_joinableState(Joinable)
81 , m_pthreadHandle(handle)
85 JoinableState joinableState() { return m_joinableState; }
86 pthread_t pthreadHandle() { return m_pthreadHandle; }
87 void didBecomeDetached() { m_joinableState = Detached; }
88 void didExit() { m_didExit = true; }
89 void didJoin() { m_joinableState = Joined; }
90 bool hasExited() { return m_didExit; }
93 JoinableState m_joinableState;
95 pthread_t m_pthreadHandle;
98 typedef HashMap<ThreadIdentifier, OwnPtr<PthreadState> > ThreadMap;
100 static Mutex* atomicallyInitializedStaticMutex;
102 void unsafeThreadWasDetached(ThreadIdentifier);
103 void threadDidExit(ThreadIdentifier);
104 void threadWasJoined(ThreadIdentifier);
106 static Mutex& threadMapMutex()
108 DEFINE_STATIC_LOCAL(Mutex, mutex, ());
112 void initializeThreading()
114 if (atomicallyInitializedStaticMutex)
117 WTF::double_conversion::initialize();
118 // StringImpl::empty() does not construct its static string in a threadsafe fashion,
119 // so ensure it has been initialized from here.
121 atomicallyInitializedStaticMutex = new Mutex;
123 initializeRandomNumberGenerator();
124 ThreadIdentifierData::initializeOnce();
126 s_dtoaP5Mutex = new Mutex;
130 void lockAtomicallyInitializedStaticMutex()
132 ASSERT(atomicallyInitializedStaticMutex);
133 atomicallyInitializedStaticMutex->lock();
136 void unlockAtomicallyInitializedStaticMutex()
138 atomicallyInitializedStaticMutex->unlock();
141 static ThreadMap& threadMap()
143 DEFINE_STATIC_LOCAL(ThreadMap, map, ());
147 static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle)
149 MutexLocker locker(threadMapMutex());
151 ThreadMap::iterator i = threadMap().begin();
152 for (; i != threadMap().end(); ++i) {
153 if (pthread_equal(i->second->pthreadHandle(), pthreadHandle) && !i->second->hasExited())
160 static ThreadIdentifier establishIdentifierForPthreadHandle(const pthread_t& pthreadHandle)
162 ASSERT(!identifierByPthreadHandle(pthreadHandle));
163 MutexLocker locker(threadMapMutex());
164 static ThreadIdentifier identifierCount = 1;
165 threadMap().add(identifierCount, adoptPtr(new PthreadState(pthreadHandle)));
166 return identifierCount++;
169 static pthread_t pthreadHandleForIdentifierWithLockAlreadyHeld(ThreadIdentifier id)
171 return threadMap().get(id)->pthreadHandle();
174 static void* wtfThreadEntryPoint(void* param)
176 // Balanced by .leakPtr() in createThreadInternal.
177 OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(static_cast<ThreadFunctionInvocation*>(param));
178 invocation->function(invocation->data);
182 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
184 OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(new ThreadFunctionInvocation(entryPoint, data));
185 pthread_t threadHandle;
186 if (pthread_create(&threadHandle, 0, wtfThreadEntryPoint, invocation.get())) {
187 LOG_ERROR("Failed to create pthread at entry point %p with data %p", wtfThreadEntryPoint, invocation.get());
191 // Balanced by adoptPtr() in wtfThreadEntryPoint.
192 ThreadFunctionInvocation* leakedInvocation = invocation.leakPtr();
193 UNUSED_PARAM(leakedInvocation);
195 return establishIdentifierForPthreadHandle(threadHandle);
198 void initializeCurrentThreadInternal(const char* threadName)
200 #if HAVE(PTHREAD_SETNAME_NP)
201 pthread_setname_np(threadName);
203 pthread_setname_np(pthread_self(), threadName);
205 UNUSED_PARAM(threadName);
208 #if OS(MAC_OS_X) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
209 // All threads that potentially use APIs above the BSD layer must be registered with the Objective-C
210 // garbage collector in case API implementations use garbage-collected memory.
211 objc_registerThreadWithCollector();
214 ThreadIdentifier id = identifierByPthreadHandle(pthread_self());
216 ThreadIdentifierData::initialize(id);
219 int waitForThreadCompletion(ThreadIdentifier threadID)
221 pthread_t pthreadHandle;
225 // We don't want to lock across the call to join, since that can block our thread and cause deadlock.
226 MutexLocker locker(threadMapMutex());
227 pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID);
228 ASSERT(pthreadHandle);
231 int joinResult = pthread_join(pthreadHandle, 0);
233 if (joinResult == EDEADLK)
234 LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
236 LOG_ERROR("ThreadIdentifier %u was unable to be joined.\n", threadID);
238 MutexLocker locker(threadMapMutex());
239 PthreadState* state = threadMap().get(threadID);
241 ASSERT(state->joinableState() == PthreadState::Joinable);
243 // The thread has already exited, so clean up after it.
244 if (state->hasExited())
245 threadMap().remove(threadID);
246 // 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.
253 void detachThread(ThreadIdentifier threadID)
257 MutexLocker locker(threadMapMutex());
258 pthread_t pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID);
259 ASSERT(pthreadHandle);
261 int detachResult = pthread_detach(pthreadHandle);
263 LOG_ERROR("ThreadIdentifier %u was unable to be detached\n", threadID);
265 PthreadState* state = threadMap().get(threadID);
267 if (state->hasExited())
268 threadMap().remove(threadID);
270 threadMap().get(threadID)->didBecomeDetached();
273 void threadDidExit(ThreadIdentifier threadID)
275 MutexLocker locker(threadMapMutex());
276 PthreadState* state = threadMap().get(threadID);
281 if (state->joinableState() != PthreadState::Joinable)
282 threadMap().remove(threadID);
290 ThreadIdentifier currentThread()
292 ThreadIdentifier id = ThreadIdentifierData::identifier();
296 // Not a WTF-created thread, ThreadIdentifier is not established yet.
297 id = establishIdentifierForPthreadHandle(pthread_self());
298 ThreadIdentifierData::initialize(id);
304 pthread_mutexattr_t attr;
305 pthread_mutexattr_init(&attr);
306 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
308 int result = pthread_mutex_init(&m_mutex, &attr);
309 ASSERT_UNUSED(result, !result);
311 pthread_mutexattr_destroy(&attr);
316 int result = pthread_mutex_destroy(&m_mutex);
317 ASSERT_UNUSED(result, !result);
322 int result = pthread_mutex_lock(&m_mutex);
323 ASSERT_UNUSED(result, !result);
326 bool Mutex::tryLock()
328 int result = pthread_mutex_trylock(&m_mutex);
335 ASSERT_NOT_REACHED();
341 int result = pthread_mutex_unlock(&m_mutex);
342 ASSERT_UNUSED(result, !result);
345 #if HAVE(PTHREAD_RWLOCK)
346 ReadWriteLock::ReadWriteLock()
348 pthread_rwlock_init(&m_readWriteLock, NULL);
351 ReadWriteLock::~ReadWriteLock()
353 pthread_rwlock_destroy(&m_readWriteLock);
356 void ReadWriteLock::readLock()
358 int result = pthread_rwlock_rdlock(&m_readWriteLock);
359 ASSERT_UNUSED(result, !result);
362 bool ReadWriteLock::tryReadLock()
364 int result = pthread_rwlock_tryrdlock(&m_readWriteLock);
368 if (result == EBUSY || result == EAGAIN)
371 ASSERT_NOT_REACHED();
375 void ReadWriteLock::writeLock()
377 int result = pthread_rwlock_wrlock(&m_readWriteLock);
378 ASSERT_UNUSED(result, !result);
381 bool ReadWriteLock::tryWriteLock()
383 int result = pthread_rwlock_trywrlock(&m_readWriteLock);
387 if (result == EBUSY || result == EAGAIN)
390 ASSERT_NOT_REACHED();
394 void ReadWriteLock::unlock()
396 int result = pthread_rwlock_unlock(&m_readWriteLock);
397 ASSERT_UNUSED(result, !result);
399 #endif // HAVE(PTHREAD_RWLOCK)
401 ThreadCondition::ThreadCondition()
403 pthread_cond_init(&m_condition, NULL);
406 ThreadCondition::~ThreadCondition()
408 pthread_cond_destroy(&m_condition);
411 void ThreadCondition::wait(Mutex& mutex)
413 int result = pthread_cond_wait(&m_condition, &mutex.impl());
414 ASSERT_UNUSED(result, !result);
417 bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
419 if (absoluteTime < currentTime())
422 if (absoluteTime > INT_MAX) {
427 int timeSeconds = static_cast<int>(absoluteTime);
428 int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9);
431 targetTime.tv_sec = timeSeconds;
432 targetTime.tv_nsec = timeNanoseconds;
434 return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0;
437 void ThreadCondition::signal()
439 int result = pthread_cond_signal(&m_condition);
440 ASSERT_UNUSED(result, !result);
443 void ThreadCondition::broadcast()
445 int result = pthread_cond_broadcast(&m_condition);
446 ASSERT_UNUSED(result, !result);
451 #endif // USE(PTHREADS)