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 "ThreadIdentifierDataPthreads.h"
44 #include "ThreadSpecific.h"
45 #include "UnusedParam.h"
46 #include <wtf/WTFThreadData.h>
55 #if OS(MAC_OS_X) && !defined(BUILDING_ON_LEOPARD)
56 #include <objc/objc-auto.h>
59 #if PLATFORM(BLACKBERRY)
60 #include <BlackBerryPlatformMisc.h>
61 #include <BlackBerryPlatformSettings.h>
66 typedef HashMap<ThreadIdentifier, pthread_t> ThreadMap;
68 static Mutex* atomicallyInitializedStaticMutex;
70 void clearPthreadHandleForIdentifier(ThreadIdentifier);
72 static Mutex& threadMapMutex()
74 DEFINE_STATIC_LOCAL(Mutex, mutex, ());
78 void initializeThreading()
80 if (atomicallyInitializedStaticMutex)
83 WTF::double_conversion::initialize();
84 // StringImpl::empty() does not construct its static string in a threadsafe fashion,
85 // so ensure it has been initialized from here.
87 atomicallyInitializedStaticMutex = new Mutex;
89 initializeRandomNumberGenerator();
90 ThreadIdentifierData::initializeOnce();
92 s_dtoaP5Mutex = new Mutex;
96 void lockAtomicallyInitializedStaticMutex()
98 ASSERT(atomicallyInitializedStaticMutex);
99 atomicallyInitializedStaticMutex->lock();
102 void unlockAtomicallyInitializedStaticMutex()
104 atomicallyInitializedStaticMutex->unlock();
107 static ThreadMap& threadMap()
109 DEFINE_STATIC_LOCAL(ThreadMap, map, ());
113 static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle)
115 MutexLocker locker(threadMapMutex());
117 ThreadMap::iterator i = threadMap().begin();
118 for (; i != threadMap().end(); ++i) {
119 if (pthread_equal(i->second, pthreadHandle))
126 static ThreadIdentifier establishIdentifierForPthreadHandle(const pthread_t& pthreadHandle)
128 ASSERT(!identifierByPthreadHandle(pthreadHandle));
130 MutexLocker locker(threadMapMutex());
132 static ThreadIdentifier identifierCount = 1;
134 threadMap().add(identifierCount, pthreadHandle);
136 return identifierCount++;
139 static pthread_t pthreadHandleForIdentifier(ThreadIdentifier id)
141 MutexLocker locker(threadMapMutex());
143 return threadMap().get(id);
146 void clearPthreadHandleForIdentifier(ThreadIdentifier id)
148 MutexLocker locker(threadMapMutex());
150 ASSERT(threadMap().contains(id));
152 threadMap().remove(id);
155 #if PLATFORM(BLACKBERRY)
156 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char* threadName)
159 if (pthread_attr_init(&attr)) {
160 LOG_ERROR("pthread_attr_init() failed: %d", errno);
166 if (pthread_attr_getstack(&attr, &stackAddr, &stackSize))
167 LOG_ERROR("pthread_attr_getstack() failed: %d", errno);
169 stackSize = BlackBerry::Platform::Settings::get()->secondaryThreadStackSize();
170 if (pthread_attr_setstack(&attr, stackAddr, stackSize))
171 LOG_ERROR("pthread_attr_getstack() failed: %d", errno);
174 pthread_t threadHandle;
175 if (pthread_create(&threadHandle, &attr, entryPoint, data)) {
176 LOG_ERROR("pthread_create() failed: %d", errno);
179 pthread_setname_np(threadHandle, threadName);
181 pthread_attr_destroy(&attr);
186 return establishIdentifierForPthreadHandle(threadHandle);
189 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
191 pthread_t threadHandle;
192 if (pthread_create(&threadHandle, 0, entryPoint, data)) {
193 LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint, data);
197 return establishIdentifierForPthreadHandle(threadHandle);
201 void initializeCurrentThreadInternal(const char* threadName)
203 #if HAVE(PTHREAD_SETNAME_NP)
204 pthread_setname_np(threadName);
206 UNUSED_PARAM(threadName);
209 #if OS(MAC_OS_X) && !defined(BUILDING_ON_LEOPARD)
210 // All threads that potentially use APIs above the BSD layer must be registered with the Objective-C
211 // garbage collector in case API implementations use garbage-collected memory.
212 objc_registerThreadWithCollector();
215 ThreadIdentifier id = identifierByPthreadHandle(pthread_self());
217 ThreadIdentifierData::initialize(id);
220 int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
224 pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
228 int joinResult = pthread_join(pthreadHandle, result);
229 if (joinResult == EDEADLK)
230 LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
235 void detachThread(ThreadIdentifier threadID)
239 pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
243 pthread_detach(pthreadHandle);
251 ThreadIdentifier currentThread()
253 ThreadIdentifier id = ThreadIdentifierData::identifier();
257 // Not a WTF-created thread, ThreadIdentifier is not established yet.
258 id = establishIdentifierForPthreadHandle(pthread_self());
259 ThreadIdentifierData::initialize(id);
265 pthread_mutexattr_t attr;
266 pthread_mutexattr_init(&attr);
267 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
269 pthread_mutex_init(&m_mutex, &attr);
271 pthread_mutexattr_destroy(&attr);
276 pthread_mutex_destroy(&m_mutex);
281 int result = pthread_mutex_lock(&m_mutex);
282 ASSERT_UNUSED(result, !result);
285 bool Mutex::tryLock()
287 int result = pthread_mutex_trylock(&m_mutex);
294 ASSERT_NOT_REACHED();
300 int result = pthread_mutex_unlock(&m_mutex);
301 ASSERT_UNUSED(result, !result);
304 #if HAVE(PTHREAD_RWLOCK)
305 ReadWriteLock::ReadWriteLock()
307 pthread_rwlock_init(&m_readWriteLock, NULL);
310 ReadWriteLock::~ReadWriteLock()
312 pthread_rwlock_destroy(&m_readWriteLock);
315 void ReadWriteLock::readLock()
317 int result = pthread_rwlock_rdlock(&m_readWriteLock);
318 ASSERT_UNUSED(result, !result);
321 bool ReadWriteLock::tryReadLock()
323 int result = pthread_rwlock_tryrdlock(&m_readWriteLock);
327 if (result == EBUSY || result == EAGAIN)
330 ASSERT_NOT_REACHED();
334 void ReadWriteLock::writeLock()
336 int result = pthread_rwlock_wrlock(&m_readWriteLock);
337 ASSERT_UNUSED(result, !result);
340 bool ReadWriteLock::tryWriteLock()
342 int result = pthread_rwlock_trywrlock(&m_readWriteLock);
346 if (result == EBUSY || result == EAGAIN)
349 ASSERT_NOT_REACHED();
353 void ReadWriteLock::unlock()
355 int result = pthread_rwlock_unlock(&m_readWriteLock);
356 ASSERT_UNUSED(result, !result);
358 #endif // HAVE(PTHREAD_RWLOCK)
360 ThreadCondition::ThreadCondition()
362 pthread_cond_init(&m_condition, NULL);
365 ThreadCondition::~ThreadCondition()
367 pthread_cond_destroy(&m_condition);
370 void ThreadCondition::wait(Mutex& mutex)
372 int result = pthread_cond_wait(&m_condition, &mutex.impl());
373 ASSERT_UNUSED(result, !result);
376 bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
378 if (absoluteTime < currentTime())
381 if (absoluteTime > INT_MAX) {
386 int timeSeconds = static_cast<int>(absoluteTime);
387 int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9);
390 targetTime.tv_sec = timeSeconds;
391 targetTime.tv_nsec = timeNanoseconds;
393 return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0;
396 void ThreadCondition::signal()
398 int result = pthread_cond_signal(&m_condition);
399 ASSERT_UNUSED(result, !result);
402 void ThreadCondition::broadcast()
404 int result = pthread_cond_broadcast(&m_condition);
405 ASSERT_UNUSED(result, !result);
410 #endif // USE(PTHREADS)