1/* 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. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 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. 18 * 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. 29 */ 30 31#include "config.h" 32#include "Threading.h" 33 34#if USE(PTHREADS) 35 36#include "CurrentTime.h" 37#include "DateMath.h" 38#include "dtoa.h" 39#include "dtoa/cached-powers.h" 40#include "HashMap.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> 50#include <errno.h> 51 52#if !COMPILER(MSVC) 53#include <limits.h> 54#include <sched.h> 55#include <sys/time.h> 56#endif 57 58#if OS(MAC_OS_X) 59#include <objc/objc-auto.h> 60#endif 61 62namespace WTF { 63 64class PthreadState { 65 WTF_MAKE_FAST_ALLOCATED; 66public: 67 enum JoinableState { 68 Joinable, // The default thread state. The thread can be joined on. 69 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). 74 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. 76 }; 77 78 // Currently all threads created by WTF start out as joinable. 79 PthreadState(pthread_t handle) 80 : m_joinableState(Joinable) 81 , m_didExit(false) 82 , m_pthreadHandle(handle) 83 { 84 } 85 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; } 92 93private: 94 JoinableState m_joinableState; 95 bool m_didExit; 96 pthread_t m_pthreadHandle; 97}; 98 99typedef HashMap<ThreadIdentifier, std::unique_ptr<PthreadState>> ThreadMap; 100 101void unsafeThreadWasDetached(ThreadIdentifier); 102void threadDidExit(ThreadIdentifier); 103void threadWasJoined(ThreadIdentifier); 104 105static Mutex& threadMapMutex() 106{ 107 DEPRECATED_DEFINE_STATIC_LOCAL(Mutex, mutex, ()); 108 return mutex; 109} 110 111void initializeThreading() 112{ 113 static bool isInitialized; 114 115 if (isInitialized) 116 return; 117 118 isInitialized = true; 119 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. 123 StringImpl::empty(); 124 threadMapMutex(); 125 initializeRandomNumberGenerator(); 126 ThreadIdentifierData::initializeOnce(); 127 StackStats::initialize(); 128 wtfThreadData(); 129 s_dtoaP5Mutex = new Mutex; 130 initializeDates(); 131} 132 133static ThreadMap& threadMap() 134{ 135 DEPRECATED_DEFINE_STATIC_LOCAL(ThreadMap, map, ()); 136 return map; 137} 138 139static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle) 140{ 141 MutexLocker locker(threadMapMutex()); 142 143 ThreadMap::iterator i = threadMap().begin(); 144 for (; i != threadMap().end(); ++i) { 145 if (pthread_equal(i->value->pthreadHandle(), pthreadHandle) && !i->value->hasExited()) 146 return i->key; 147 } 148 149 return 0; 150} 151 152static ThreadIdentifier establishIdentifierForPthreadHandle(const pthread_t& pthreadHandle) 153{ 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++; 159} 160 161static pthread_t pthreadHandleForIdentifierWithLockAlreadyHeld(ThreadIdentifier id) 162{ 163 return threadMap().get(id)->pthreadHandle(); 164} 165 166static void* wtfThreadEntryPoint(void* param) 167{ 168 // Balanced by .leakPtr() in createThreadInternal. 169 auto invocation = std::unique_ptr<ThreadFunctionInvocation>(static_cast<ThreadFunctionInvocation*>(param)); 170 invocation->function(invocation->data); 171 return nullptr; 172} 173 174ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*) 175{ 176 auto invocation = std::make_unique<ThreadFunctionInvocation>(entryPoint, data); 177 pthread_t threadHandle; 178 pthread_attr_t attr; 179 pthread_attr_init(&attr); 180#if HAVE(QOS_CLASSES) 181 pthread_attr_set_qos_class_np(&attr, QOS_CLASS_USER_INITIATED, 0); 182#endif 183 int error = pthread_create(&threadHandle, &attr, wtfThreadEntryPoint, invocation.get()); 184 pthread_attr_destroy(&attr); 185 if (error) { 186 LOG_ERROR("Failed to create pthread at entry point %p with data %p", wtfThreadEntryPoint, invocation.get()); 187 return 0; 188 } 189 190 // Balanced by std::unique_ptr constructor in wtfThreadEntryPoint. 191 ThreadFunctionInvocation* leakedInvocation = invocation.release(); 192 UNUSED_PARAM(leakedInvocation); 193 194 return establishIdentifierForPthreadHandle(threadHandle); 195} 196 197void initializeCurrentThreadInternal(const char* threadName) 198{ 199#if HAVE(PTHREAD_SETNAME_NP) 200 pthread_setname_np(threadName); 201#else 202 UNUSED_PARAM(threadName); 203#endif 204 205#if OS(MAC_OS_X) 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(); 209#endif 210 211 ThreadIdentifier id = identifierByPthreadHandle(pthread_self()); 212 ASSERT(id); 213 ThreadIdentifierData::initialize(id); 214} 215 216void changeThreadPriority(ThreadIdentifier threadID, int delta) 217{ 218 pthread_t pthreadHandle; 219 ASSERT(threadID); 220 221 { 222 MutexLocker locker(threadMapMutex()); 223 pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID); 224 ASSERT(pthreadHandle); 225 } 226 227 int policy; 228 struct sched_param param; 229 230 if (pthread_getschedparam(pthreadHandle, &policy, ¶m)) 231 return; 232 233 param.sched_priority += delta; 234 235 pthread_setschedparam(pthreadHandle, policy, ¶m); 236} 237 238int waitForThreadCompletion(ThreadIdentifier threadID) 239{ 240 pthread_t pthreadHandle; 241 ASSERT(threadID); 242 243 { 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); 248 } 249 250 int joinResult = pthread_join(pthreadHandle, 0); 251 252 if (joinResult == EDEADLK) 253 LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID); 254 else if (joinResult) 255 LOG_ERROR("ThreadIdentifier %u was unable to be joined.\n", threadID); 256 257 MutexLocker locker(threadMapMutex()); 258 PthreadState* state = threadMap().get(threadID); 259 ASSERT(state); 260 ASSERT(state->joinableState() == PthreadState::Joinable); 261 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. 266 else 267 state->didJoin(); 268 269 return joinResult; 270} 271 272void detachThread(ThreadIdentifier threadID) 273{ 274 ASSERT(threadID); 275 276 MutexLocker locker(threadMapMutex()); 277 pthread_t pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID); 278 ASSERT(pthreadHandle); 279 280 int detachResult = pthread_detach(pthreadHandle); 281 if (detachResult) 282 LOG_ERROR("ThreadIdentifier %u was unable to be detached\n", threadID); 283 284 PthreadState* state = threadMap().get(threadID); 285 ASSERT(state); 286 if (state->hasExited()) 287 threadMap().remove(threadID); 288 else 289 threadMap().get(threadID)->didBecomeDetached(); 290} 291 292void threadDidExit(ThreadIdentifier threadID) 293{ 294 MutexLocker locker(threadMapMutex()); 295 PthreadState* state = threadMap().get(threadID); 296 ASSERT(state); 297 298 state->didExit(); 299 300 if (state->joinableState() != PthreadState::Joinable) 301 threadMap().remove(threadID); 302} 303 304ThreadIdentifier currentThread() 305{ 306 ThreadIdentifier id = ThreadIdentifierData::identifier(); 307 if (id) 308 return id; 309 310 // Not a WTF-created thread, ThreadIdentifier is not established yet. 311 id = establishIdentifierForPthreadHandle(pthread_self()); 312 ThreadIdentifierData::initialize(id); 313 return id; 314} 315 316Mutex::Mutex() 317{ 318 pthread_mutexattr_t attr; 319 pthread_mutexattr_init(&attr); 320 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); 321 322 int result = pthread_mutex_init(&m_mutex, &attr); 323 ASSERT_UNUSED(result, !result); 324 325 pthread_mutexattr_destroy(&attr); 326} 327 328Mutex::~Mutex() 329{ 330 int result = pthread_mutex_destroy(&m_mutex); 331 ASSERT_UNUSED(result, !result); 332} 333 334void Mutex::lock() 335{ 336 int result = pthread_mutex_lock(&m_mutex); 337 ASSERT_UNUSED(result, !result); 338} 339 340bool Mutex::tryLock() 341{ 342 int result = pthread_mutex_trylock(&m_mutex); 343 344 if (result == 0) 345 return true; 346 if (result == EBUSY) 347 return false; 348 349 ASSERT_NOT_REACHED(); 350 return false; 351} 352 353void Mutex::unlock() 354{ 355 int result = pthread_mutex_unlock(&m_mutex); 356 ASSERT_UNUSED(result, !result); 357} 358 359ThreadCondition::ThreadCondition() 360{ 361 pthread_cond_init(&m_condition, NULL); 362} 363 364ThreadCondition::~ThreadCondition() 365{ 366 pthread_cond_destroy(&m_condition); 367} 368 369void ThreadCondition::wait(Mutex& mutex) 370{ 371 int result = pthread_cond_wait(&m_condition, &mutex.impl()); 372 ASSERT_UNUSED(result, !result); 373} 374 375bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime) 376{ 377 if (absoluteTime < currentTime()) 378 return false; 379 380 if (absoluteTime > INT_MAX) { 381 wait(mutex); 382 return true; 383 } 384 385 int timeSeconds = static_cast<int>(absoluteTime); 386 int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9); 387 388 timespec targetTime; 389 targetTime.tv_sec = timeSeconds; 390 targetTime.tv_nsec = timeNanoseconds; 391 392 return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0; 393} 394 395void ThreadCondition::signal() 396{ 397 int result = pthread_cond_signal(&m_condition); 398 ASSERT_UNUSED(result, !result); 399} 400 401void ThreadCondition::broadcast() 402{ 403 int result = pthread_cond_broadcast(&m_condition); 404 ASSERT_UNUSED(result, !result); 405} 406 407} // namespace WTF 408 409#endif // USE(PTHREADS) 410