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 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 "StackStats.h"
43 #include "StdLibExtras.h"
44 #include "ThreadFunctionInvocation.h"
45 #include "ThreadIdentifierDataPthreads.h"
46 #include "ThreadSpecific.h"
47 #include <wtf/DataLog.h>
48 #include <wtf/RawPointer.h>
49 #include <wtf/WTFThreadData.h>
59 #include <objc/objc-auto.h>
65 WTF_MAKE_FAST_ALLOCATED;
68 Joinable, // The default thread state. The thread can be joined on.
70 Joined, // Somebody waited on this thread to exit and this thread finally exited. This state is here because there can be a
71 // period of time between when the thread exits (which causes pthread_join to return and the remainder of waitOnThreadCompletion to run)
72 // and when threadDidExit is called. We need threadDidExit to take charge and delete the thread data since there's
73 // nobody else to pick up the slack in this case (since waitOnThreadCompletion has already returned).
75 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.
78 // Currently all threads created by WTF start out as joinable.
79 PthreadState(pthread_t handle)
80 : m_joinableState(Joinable)
82 , m_pthreadHandle(handle)
86 JoinableState joinableState() { return m_joinableState; }
87 pthread_t pthreadHandle() { return m_pthreadHandle; }
88 void didBecomeDetached() { m_joinableState = Detached; }
89 void didExit() { m_didExit = true; }
90 void didJoin() { m_joinableState = Joined; }
91 bool hasExited() { return m_didExit; }
94 JoinableState m_joinableState;
96 pthread_t m_pthreadHandle;
99 typedef HashMap<ThreadIdentifier, std::unique_ptr<PthreadState>> ThreadMap;
101 void unsafeThreadWasDetached(ThreadIdentifier);
102 void threadDidExit(ThreadIdentifier);
103 void threadWasJoined(ThreadIdentifier);
105 static Mutex& threadMapMutex()
107 DEPRECATED_DEFINE_STATIC_LOCAL(Mutex, mutex, ());
111 void initializeThreading()
113 static bool isInitialized;
118 isInitialized = true;
120 WTF::double_conversion::initialize();
121 // StringImpl::empty() does not construct its static string in a threadsafe fashion,
122 // so ensure it has been initialized from here.
125 initializeRandomNumberGenerator();
126 ThreadIdentifierData::initializeOnce();
127 StackStats::initialize();
129 s_dtoaP5Mutex = new Mutex;
133 static ThreadMap& threadMap()
135 DEPRECATED_DEFINE_STATIC_LOCAL(ThreadMap, map, ());
139 static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle)
141 MutexLocker locker(threadMapMutex());
143 ThreadMap::iterator i = threadMap().begin();
144 for (; i != threadMap().end(); ++i) {
145 if (pthread_equal(i->value->pthreadHandle(), pthreadHandle) && !i->value->hasExited())
152 static ThreadIdentifier establishIdentifierForPthreadHandle(const pthread_t& pthreadHandle)
154 ASSERT(!identifierByPthreadHandle(pthreadHandle));
155 MutexLocker locker(threadMapMutex());
156 static ThreadIdentifier identifierCount = 1;
157 threadMap().add(identifierCount, std::make_unique<PthreadState>(pthreadHandle));
158 return identifierCount++;
161 static pthread_t pthreadHandleForIdentifierWithLockAlreadyHeld(ThreadIdentifier id)
163 return threadMap().get(id)->pthreadHandle();
166 static void* wtfThreadEntryPoint(void* param)
168 // Balanced by .leakPtr() in createThreadInternal.
169 auto invocation = std::unique_ptr<ThreadFunctionInvocation>(static_cast<ThreadFunctionInvocation*>(param));
170 invocation->function(invocation->data);
174 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
176 auto invocation = std::make_unique<ThreadFunctionInvocation>(entryPoint, data);
177 pthread_t threadHandle;
179 pthread_attr_init(&attr);
180 #if HAVE(QOS_CLASSES)
181 pthread_attr_set_qos_class_np(&attr, QOS_CLASS_USER_INITIATED, 0);
183 int error = pthread_create(&threadHandle, &attr, wtfThreadEntryPoint, invocation.get());
184 pthread_attr_destroy(&attr);
186 LOG_ERROR("Failed to create pthread at entry point %p with data %p", wtfThreadEntryPoint, invocation.get());
190 // Balanced by std::unique_ptr constructor in wtfThreadEntryPoint.
191 ThreadFunctionInvocation* leakedInvocation = invocation.release();
192 UNUSED_PARAM(leakedInvocation);
194 return establishIdentifierForPthreadHandle(threadHandle);
197 void initializeCurrentThreadInternal(const char* threadName)
199 #if HAVE(PTHREAD_SETNAME_NP)
200 pthread_setname_np(threadName);
202 UNUSED_PARAM(threadName);
206 // All threads that potentially use APIs above the BSD layer must be registered with the Objective-C
207 // garbage collector in case API implementations use garbage-collected memory.
208 objc_registerThreadWithCollector();
211 ThreadIdentifier id = identifierByPthreadHandle(pthread_self());
213 ThreadIdentifierData::initialize(id);
216 void changeThreadPriority(ThreadIdentifier threadID, int delta)
218 pthread_t pthreadHandle;
222 MutexLocker locker(threadMapMutex());
223 pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID);
224 ASSERT(pthreadHandle);
228 struct sched_param param;
230 if (pthread_getschedparam(pthreadHandle, &policy, ¶m))
233 param.sched_priority += delta;
235 pthread_setschedparam(pthreadHandle, policy, ¶m);
238 int waitForThreadCompletion(ThreadIdentifier threadID)
240 pthread_t pthreadHandle;
244 // We don't want to lock across the call to join, since that can block our thread and cause deadlock.
245 MutexLocker locker(threadMapMutex());
246 pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID);
247 ASSERT(pthreadHandle);
250 int joinResult = pthread_join(pthreadHandle, 0);
252 if (joinResult == EDEADLK)
253 LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
255 LOG_ERROR("ThreadIdentifier %u was unable to be joined.\n", threadID);
257 MutexLocker locker(threadMapMutex());
258 PthreadState* state = threadMap().get(threadID);
260 ASSERT(state->joinableState() == PthreadState::Joinable);
262 // The thread has already exited, so clean up after it.
263 if (state->hasExited())
264 threadMap().remove(threadID);
265 // 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.
272 void detachThread(ThreadIdentifier threadID)
276 MutexLocker locker(threadMapMutex());
277 pthread_t pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID);
278 ASSERT(pthreadHandle);
280 int detachResult = pthread_detach(pthreadHandle);
282 LOG_ERROR("ThreadIdentifier %u was unable to be detached\n", threadID);
284 PthreadState* state = threadMap().get(threadID);
286 if (state->hasExited())
287 threadMap().remove(threadID);
289 threadMap().get(threadID)->didBecomeDetached();
292 void threadDidExit(ThreadIdentifier threadID)
294 MutexLocker locker(threadMapMutex());
295 PthreadState* state = threadMap().get(threadID);
300 if (state->joinableState() != PthreadState::Joinable)
301 threadMap().remove(threadID);
304 ThreadIdentifier currentThread()
306 ThreadIdentifier id = ThreadIdentifierData::identifier();
310 // Not a WTF-created thread, ThreadIdentifier is not established yet.
311 id = establishIdentifierForPthreadHandle(pthread_self());
312 ThreadIdentifierData::initialize(id);
318 pthread_mutexattr_t attr;
319 pthread_mutexattr_init(&attr);
320 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
322 int result = pthread_mutex_init(&m_mutex, &attr);
323 ASSERT_UNUSED(result, !result);
325 pthread_mutexattr_destroy(&attr);
330 int result = pthread_mutex_destroy(&m_mutex);
331 ASSERT_UNUSED(result, !result);
336 int result = pthread_mutex_lock(&m_mutex);
337 ASSERT_UNUSED(result, !result);
340 bool Mutex::tryLock()
342 int result = pthread_mutex_trylock(&m_mutex);
349 ASSERT_NOT_REACHED();
355 int result = pthread_mutex_unlock(&m_mutex);
356 ASSERT_UNUSED(result, !result);
359 ThreadCondition::ThreadCondition()
361 pthread_cond_init(&m_condition, NULL);
364 ThreadCondition::~ThreadCondition()
366 pthread_cond_destroy(&m_condition);
369 void ThreadCondition::wait(Mutex& mutex)
371 int result = pthread_cond_wait(&m_condition, &mutex.impl());
372 ASSERT_UNUSED(result, !result);
375 bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
377 if (absoluteTime < currentTime())
380 if (absoluteTime > INT_MAX) {
385 int timeSeconds = static_cast<int>(absoluteTime);
386 int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9);
389 targetTime.tv_sec = timeSeconds;
390 targetTime.tv_nsec = timeNanoseconds;
392 return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0;
395 void ThreadCondition::signal()
397 int result = pthread_cond_signal(&m_condition);
398 ASSERT_UNUSED(result, !result);
401 void ThreadCondition::broadcast()
403 int result = pthread_cond_broadcast(&m_condition);
404 ASSERT_UNUSED(result, !result);
409 #endif // USE(PTHREADS)