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>
64 typedef HashMap<ThreadIdentifier, pthread_t> ThreadMap;
66 static Mutex* atomicallyInitializedStaticMutex;
68 void clearPthreadHandleForIdentifier(ThreadIdentifier);
70 static Mutex& threadMapMutex()
72 DEFINE_STATIC_LOCAL(Mutex, mutex, ());
76 void initializeThreading()
78 if (atomicallyInitializedStaticMutex)
81 WTF::double_conversion::initialize();
82 // StringImpl::empty() does not construct its static string in a threadsafe fashion,
83 // so ensure it has been initialized from here.
85 atomicallyInitializedStaticMutex = new Mutex;
87 initializeRandomNumberGenerator();
88 ThreadIdentifierData::initializeOnce();
90 s_dtoaP5Mutex = new Mutex;
94 void lockAtomicallyInitializedStaticMutex()
96 ASSERT(atomicallyInitializedStaticMutex);
97 atomicallyInitializedStaticMutex->lock();
100 void unlockAtomicallyInitializedStaticMutex()
102 atomicallyInitializedStaticMutex->unlock();
105 static ThreadMap& threadMap()
107 DEFINE_STATIC_LOCAL(ThreadMap, map, ());
111 static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle)
113 MutexLocker locker(threadMapMutex());
115 ThreadMap::iterator i = threadMap().begin();
116 for (; i != threadMap().end(); ++i) {
117 if (pthread_equal(i->second, pthreadHandle))
124 static ThreadIdentifier establishIdentifierForPthreadHandle(const pthread_t& pthreadHandle)
126 ASSERT(!identifierByPthreadHandle(pthreadHandle));
128 MutexLocker locker(threadMapMutex());
130 static ThreadIdentifier identifierCount = 1;
132 threadMap().add(identifierCount, pthreadHandle);
134 return identifierCount++;
137 static pthread_t pthreadHandleForIdentifier(ThreadIdentifier id)
139 MutexLocker locker(threadMapMutex());
141 return threadMap().get(id);
144 void clearPthreadHandleForIdentifier(ThreadIdentifier id)
146 MutexLocker locker(threadMapMutex());
148 ASSERT(threadMap().contains(id));
150 threadMap().remove(id);
153 static void* wtfThreadEntryPoint(void* param)
155 // Balanced by .leakPtr() in createThreadInternal.
156 OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(static_cast<ThreadFunctionInvocation*>(param));
157 invocation->function(invocation->data);
162 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
164 OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(new ThreadFunctionInvocation(entryPoint, data));
165 pthread_t threadHandle;
166 if (pthread_create(&threadHandle, 0, wtfThreadEntryPoint, invocation.get())) {
167 LOG_ERROR("Failed to create pthread at entry point %p with data %p", wtfThreadEntryPoint, invocation.get());
171 // Balanced by adoptPtr() in wtfThreadEntryPoint.
172 ThreadFunctionInvocation* leakedInvocation = invocation.leakPtr();
173 UNUSED_PARAM(leakedInvocation);
175 return establishIdentifierForPthreadHandle(threadHandle);
178 void initializeCurrentThreadInternal(const char* threadName)
180 #if HAVE(PTHREAD_SETNAME_NP)
181 pthread_setname_np(threadName);
183 pthread_setname_np(pthread_self(), threadName);
185 UNUSED_PARAM(threadName);
188 #if OS(MAC_OS_X) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
189 // All threads that potentially use APIs above the BSD layer must be registered with the Objective-C
190 // garbage collector in case API implementations use garbage-collected memory.
191 objc_registerThreadWithCollector();
194 ThreadIdentifier id = identifierByPthreadHandle(pthread_self());
196 ThreadIdentifierData::initialize(id);
199 int waitForThreadCompletion(ThreadIdentifier threadID)
203 pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
207 int joinResult = pthread_join(pthreadHandle, 0);
208 if (joinResult == EDEADLK)
209 LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
214 void detachThread(ThreadIdentifier threadID)
218 pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
222 pthread_detach(pthreadHandle);
230 ThreadIdentifier currentThread()
232 ThreadIdentifier id = ThreadIdentifierData::identifier();
236 // Not a WTF-created thread, ThreadIdentifier is not established yet.
237 id = establishIdentifierForPthreadHandle(pthread_self());
238 ThreadIdentifierData::initialize(id);
244 pthread_mutexattr_t attr;
245 pthread_mutexattr_init(&attr);
246 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
248 int result = pthread_mutex_init(&m_mutex, &attr);
249 ASSERT_UNUSED(result, !result);
251 pthread_mutexattr_destroy(&attr);
256 int result = pthread_mutex_destroy(&m_mutex);
257 ASSERT_UNUSED(result, !result);
262 int result = pthread_mutex_lock(&m_mutex);
263 ASSERT_UNUSED(result, !result);
266 bool Mutex::tryLock()
268 int result = pthread_mutex_trylock(&m_mutex);
275 ASSERT_NOT_REACHED();
281 int result = pthread_mutex_unlock(&m_mutex);
282 ASSERT_UNUSED(result, !result);
285 #if HAVE(PTHREAD_RWLOCK)
286 ReadWriteLock::ReadWriteLock()
288 pthread_rwlock_init(&m_readWriteLock, NULL);
291 ReadWriteLock::~ReadWriteLock()
293 pthread_rwlock_destroy(&m_readWriteLock);
296 void ReadWriteLock::readLock()
298 int result = pthread_rwlock_rdlock(&m_readWriteLock);
299 ASSERT_UNUSED(result, !result);
302 bool ReadWriteLock::tryReadLock()
304 int result = pthread_rwlock_tryrdlock(&m_readWriteLock);
308 if (result == EBUSY || result == EAGAIN)
311 ASSERT_NOT_REACHED();
315 void ReadWriteLock::writeLock()
317 int result = pthread_rwlock_wrlock(&m_readWriteLock);
318 ASSERT_UNUSED(result, !result);
321 bool ReadWriteLock::tryWriteLock()
323 int result = pthread_rwlock_trywrlock(&m_readWriteLock);
327 if (result == EBUSY || result == EAGAIN)
330 ASSERT_NOT_REACHED();
334 void ReadWriteLock::unlock()
336 int result = pthread_rwlock_unlock(&m_readWriteLock);
337 ASSERT_UNUSED(result, !result);
339 #endif // HAVE(PTHREAD_RWLOCK)
341 ThreadCondition::ThreadCondition()
343 pthread_cond_init(&m_condition, NULL);
346 ThreadCondition::~ThreadCondition()
348 pthread_cond_destroy(&m_condition);
351 void ThreadCondition::wait(Mutex& mutex)
353 int result = pthread_cond_wait(&m_condition, &mutex.impl());
354 ASSERT_UNUSED(result, !result);
357 bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
359 if (absoluteTime < currentTime())
362 if (absoluteTime > INT_MAX) {
367 int timeSeconds = static_cast<int>(absoluteTime);
368 int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9);
371 targetTime.tv_sec = timeSeconds;
372 targetTime.tv_nsec = timeNanoseconds;
374 return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0;
377 void ThreadCondition::signal()
379 int result = pthread_cond_signal(&m_condition);
380 ASSERT_UNUSED(result, !result);
383 void ThreadCondition::broadcast()
385 int result = pthread_cond_broadcast(&m_condition);
386 ASSERT_UNUSED(result, !result);
391 #endif // USE(PTHREADS)