2 * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "Threading.h"
35 #include "CurrentTime.h"
38 #include "dtoa/cached-powers.h"
40 #include "RandomNumberSeed.h"
41 #include "StdLibExtras.h"
42 #include "ThreadIdentifierDataPthreads.h"
43 #include "ThreadSpecific.h"
44 #include "UnusedParam.h"
45 #include <wtf/WTFThreadData.h>
54 #if OS(MAC_OS_X) && !defined(BUILDING_ON_LEOPARD)
55 #include <objc/objc-auto.h>
60 typedef HashMap<ThreadIdentifier, pthread_t> ThreadMap;
62 static Mutex* atomicallyInitializedStaticMutex;
64 void clearPthreadHandleForIdentifier(ThreadIdentifier);
66 static Mutex& threadMapMutex()
68 DEFINE_STATIC_LOCAL(Mutex, mutex, ());
72 void initializeThreading()
74 if (atomicallyInitializedStaticMutex)
77 WTF::double_conversion::initialize();
78 // StringImpl::empty() does not construct its static string in a threadsafe fashion,
79 // so ensure it has been initialized from here.
81 atomicallyInitializedStaticMutex = new Mutex;
83 initializeRandomNumberGenerator();
84 ThreadIdentifierData::initializeOnce();
86 #if ENABLE(WTF_MULTIPLE_THREADS)
87 s_dtoaP5Mutex = new Mutex;
92 void lockAtomicallyInitializedStaticMutex()
94 ASSERT(atomicallyInitializedStaticMutex);
95 atomicallyInitializedStaticMutex->lock();
98 void unlockAtomicallyInitializedStaticMutex()
100 atomicallyInitializedStaticMutex->unlock();
103 static ThreadMap& threadMap()
105 DEFINE_STATIC_LOCAL(ThreadMap, map, ());
109 static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle)
111 MutexLocker locker(threadMapMutex());
113 ThreadMap::iterator i = threadMap().begin();
114 for (; i != threadMap().end(); ++i) {
115 if (pthread_equal(i->second, pthreadHandle))
122 static ThreadIdentifier establishIdentifierForPthreadHandle(const pthread_t& pthreadHandle)
124 ASSERT(!identifierByPthreadHandle(pthreadHandle));
126 MutexLocker locker(threadMapMutex());
128 static ThreadIdentifier identifierCount = 1;
130 threadMap().add(identifierCount, pthreadHandle);
132 return identifierCount++;
135 static pthread_t pthreadHandleForIdentifier(ThreadIdentifier id)
137 MutexLocker locker(threadMapMutex());
139 return threadMap().get(id);
142 void clearPthreadHandleForIdentifier(ThreadIdentifier id)
144 MutexLocker locker(threadMapMutex());
146 ASSERT(threadMap().contains(id));
148 threadMap().remove(id);
151 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
153 pthread_t threadHandle;
154 if (pthread_create(&threadHandle, 0, entryPoint, data)) {
155 LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint, data);
159 return establishIdentifierForPthreadHandle(threadHandle);
162 void initializeCurrentThreadInternal(const char* threadName)
164 #if HAVE(PTHREAD_SETNAME_NP)
165 pthread_setname_np(threadName);
167 UNUSED_PARAM(threadName);
170 #if OS(MAC_OS_X) && !defined(BUILDING_ON_LEOPARD)
171 // All threads that potentially use APIs above the BSD layer must be registered with the Objective-C
172 // garbage collector in case API implementations use garbage-collected memory.
173 objc_registerThreadWithCollector();
176 ThreadIdentifier id = identifierByPthreadHandle(pthread_self());
178 ThreadIdentifierData::initialize(id);
181 int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
185 pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
189 int joinResult = pthread_join(pthreadHandle, result);
190 if (joinResult == EDEADLK)
191 LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
196 void detachThread(ThreadIdentifier threadID)
200 pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
204 pthread_detach(pthreadHandle);
212 ThreadIdentifier currentThread()
214 ThreadIdentifier id = ThreadIdentifierData::identifier();
218 // Not a WTF-created thread, ThreadIdentifier is not established yet.
219 id = establishIdentifierForPthreadHandle(pthread_self());
220 ThreadIdentifierData::initialize(id);
226 pthread_mutexattr_t attr;
227 pthread_mutexattr_init(&attr);
228 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
230 pthread_mutex_init(&m_mutex, &attr);
232 pthread_mutexattr_destroy(&attr);
237 pthread_mutex_destroy(&m_mutex);
242 int result = pthread_mutex_lock(&m_mutex);
243 ASSERT_UNUSED(result, !result);
246 bool Mutex::tryLock()
248 int result = pthread_mutex_trylock(&m_mutex);
255 ASSERT_NOT_REACHED();
261 int result = pthread_mutex_unlock(&m_mutex);
262 ASSERT_UNUSED(result, !result);
265 #if HAVE(PTHREAD_RWLOCK)
266 ReadWriteLock::ReadWriteLock()
268 pthread_rwlock_init(&m_readWriteLock, NULL);
271 ReadWriteLock::~ReadWriteLock()
273 pthread_rwlock_destroy(&m_readWriteLock);
276 void ReadWriteLock::readLock()
278 int result = pthread_rwlock_rdlock(&m_readWriteLock);
279 ASSERT_UNUSED(result, !result);
282 bool ReadWriteLock::tryReadLock()
284 int result = pthread_rwlock_tryrdlock(&m_readWriteLock);
288 if (result == EBUSY || result == EAGAIN)
291 ASSERT_NOT_REACHED();
295 void ReadWriteLock::writeLock()
297 int result = pthread_rwlock_wrlock(&m_readWriteLock);
298 ASSERT_UNUSED(result, !result);
301 bool ReadWriteLock::tryWriteLock()
303 int result = pthread_rwlock_trywrlock(&m_readWriteLock);
307 if (result == EBUSY || result == EAGAIN)
310 ASSERT_NOT_REACHED();
314 void ReadWriteLock::unlock()
316 int result = pthread_rwlock_unlock(&m_readWriteLock);
317 ASSERT_UNUSED(result, !result);
319 #endif // HAVE(PTHREAD_RWLOCK)
321 ThreadCondition::ThreadCondition()
323 pthread_cond_init(&m_condition, NULL);
326 ThreadCondition::~ThreadCondition()
328 pthread_cond_destroy(&m_condition);
331 void ThreadCondition::wait(Mutex& mutex)
333 int result = pthread_cond_wait(&m_condition, &mutex.impl());
334 ASSERT_UNUSED(result, !result);
337 bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
339 if (absoluteTime < currentTime())
342 if (absoluteTime > INT_MAX) {
347 int timeSeconds = static_cast<int>(absoluteTime);
348 int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9);
351 targetTime.tv_sec = timeSeconds;
352 targetTime.tv_nsec = timeNanoseconds;
354 return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0;
357 void ThreadCondition::signal()
359 int result = pthread_cond_signal(&m_condition);
360 ASSERT_UNUSED(result, !result);
363 void ThreadCondition::broadcast()
365 int result = pthread_cond_broadcast(&m_condition);
366 ASSERT_UNUSED(result, !result);
371 #endif // USE(PTHREADS)