1 /* 2 * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. 3 * Copyright (C) 2007 Justin Haygood (jhaygood (at) 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 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. 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 "wtf/Threading.h" 33 34 #if USE(PTHREADS) 35 36 #include "wtf/DateMath.h" 37 #include "wtf/HashMap.h" 38 #include "wtf/OwnPtr.h" 39 #include "wtf/PassOwnPtr.h" 40 #include "wtf/StdLibExtras.h" 41 #include "wtf/ThreadFunctionInvocation.h" 42 #include "wtf/ThreadIdentifierDataPthreads.h" 43 #include "wtf/ThreadSpecific.h" 44 #include "wtf/ThreadingPrimitives.h" 45 #include "wtf/WTFThreadData.h" 46 #include "wtf/dtoa.h" 47 #include "wtf/dtoa/cached-powers.h" 48 #include <errno.h> 49 50 #if !COMPILER(MSVC) 51 #include <limits.h> 52 #include <sched.h> 53 #include <sys/time.h> 54 #endif 55 56 #if OS(MACOSX) 57 #include <objc/objc-auto.h> 58 #endif 59 60 namespace WTF { 61 62 class PthreadState { 63 WTF_MAKE_FAST_ALLOCATED; 64 public: 65 enum JoinableState { 66 Joinable, // The default thread state. The thread can be joined on. 67 68 Joined, // Somebody waited on this thread to exit and this thread finally exited. This state is here because there can be a 69 // period of time between when the thread exits (which causes pthread_join to return and the remainder of waitOnThreadCompletion to run) 70 // and when threadDidExit is called. We need threadDidExit to take charge and delete the thread data since there's 71 // nobody else to pick up the slack in this case (since waitOnThreadCompletion has already returned). 72 73 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. 74 }; 75 76 // Currently all threads created by WTF start out as joinable. 77 PthreadState(pthread_t handle) 78 : m_joinableState(Joinable) 79 , m_didExit(false) 80 , m_pthreadHandle(handle) 81 { 82 } 83 84 JoinableState joinableState() { return m_joinableState; } 85 pthread_t pthreadHandle() { return m_pthreadHandle; } 86 void didBecomeDetached() { m_joinableState = Detached; } 87 void didExit() { m_didExit = true; } 88 void didJoin() { m_joinableState = Joined; } 89 bool hasExited() { return m_didExit; } 90 91 private: 92 JoinableState m_joinableState; 93 bool m_didExit; 94 pthread_t m_pthreadHandle; 95 }; 96 97 typedef HashMap<ThreadIdentifier, OwnPtr<PthreadState> > ThreadMap; 98 99 static Mutex* atomicallyInitializedStaticMutex; 100 101 void unsafeThreadWasDetached(ThreadIdentifier); 102 void threadDidExit(ThreadIdentifier); 103 void threadWasJoined(ThreadIdentifier); 104 105 static Mutex& threadMapMutex() 106 { 107 DEFINE_STATIC_LOCAL(Mutex, mutex, ()); 108 return mutex; 109 } 110 111 void initializeThreading() 112 { 113 // This should only be called once. 114 ASSERT(!atomicallyInitializedStaticMutex); 115 116 // StringImpl::empty() does not construct its static string in a threadsafe fashion, 117 // so ensure it has been initialized from here. 118 StringImpl::empty(); 119 atomicallyInitializedStaticMutex = new Mutex; 120 threadMapMutex(); 121 ThreadIdentifierData::initializeOnce(); 122 wtfThreadData(); 123 s_dtoaP5Mutex = new Mutex; 124 initializeDates(); 125 } 126 127 void lockAtomicallyInitializedStaticMutex() 128 { 129 ASSERT(atomicallyInitializedStaticMutex); 130 atomicallyInitializedStaticMutex->lock(); 131 } 132 133 void unlockAtomicallyInitializedStaticMutex() 134 { 135 atomicallyInitializedStaticMutex->unlock(); 136 } 137 138 static ThreadMap& threadMap() 139 { 140 DEFINE_STATIC_LOCAL(ThreadMap, map, ()); 141 return map; 142 } 143 144 static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle) 145 { 146 MutexLocker locker(threadMapMutex()); 147 148 ThreadMap::iterator i = threadMap().begin(); 149 for (; i != threadMap().end(); ++i) { 150 if (pthread_equal(i->value->pthreadHandle(), pthreadHandle) && !i->value->hasExited()) 151 return i->key; 152 } 153 154 return 0; 155 } 156 157 static ThreadIdentifier establishIdentifierForPthreadHandle(const pthread_t& pthreadHandle) 158 { 159 ASSERT(!identifierByPthreadHandle(pthreadHandle)); 160 MutexLocker locker(threadMapMutex()); 161 static ThreadIdentifier identifierCount = 1; 162 threadMap().add(identifierCount, adoptPtr(new PthreadState(pthreadHandle))); 163 return identifierCount++; 164 } 165 166 static pthread_t pthreadHandleForIdentifierWithLockAlreadyHeld(ThreadIdentifier id) 167 { 168 return threadMap().get(id)->pthreadHandle(); 169 } 170 171 static void* wtfThreadEntryPoint(void* param) 172 { 173 // Balanced by .leakPtr() in createThreadInternal. 174 OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(static_cast<ThreadFunctionInvocation*>(param)); 175 invocation->function(invocation->data); 176 return 0; 177 } 178 179 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*) 180 { 181 OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(new ThreadFunctionInvocation(entryPoint, data)); 182 pthread_t threadHandle; 183 if (pthread_create(&threadHandle, 0, wtfThreadEntryPoint, invocation.get())) { 184 WTF_LOG_ERROR("Failed to create pthread at entry point %p with data %p", wtfThreadEntryPoint, invocation.get()); 185 return 0; 186 } 187 188 // Balanced by adoptPtr() in wtfThreadEntryPoint. 189 ThreadFunctionInvocation* ALLOW_UNUSED leakedInvocation = invocation.leakPtr(); 190 191 return establishIdentifierForPthreadHandle(threadHandle); 192 } 193 194 void initializeCurrentThreadInternal(const char* threadName) 195 { 196 #if HAVE(PTHREAD_SETNAME_NP) 197 pthread_setname_np(threadName); 198 #endif 199 200 #if OS(MACOSX) 201 // All threads that potentially use APIs above the BSD layer must be registered with the Objective-C 202 // garbage collector in case API implementations use garbage-collected memory. 203 objc_registerThreadWithCollector(); 204 #endif 205 206 ThreadIdentifier id = identifierByPthreadHandle(pthread_self()); 207 ASSERT(id); 208 ThreadIdentifierData::initialize(id); 209 } 210 211 int waitForThreadCompletion(ThreadIdentifier threadID) 212 { 213 pthread_t pthreadHandle; 214 ASSERT(threadID); 215 216 { 217 // We don't want to lock across the call to join, since that can block our thread and cause deadlock. 218 MutexLocker locker(threadMapMutex()); 219 pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID); 220 ASSERT(pthreadHandle); 221 } 222 223 int joinResult = pthread_join(pthreadHandle, 0); 224 225 if (joinResult == EDEADLK) 226 WTF_LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID); 227 else if (joinResult) 228 WTF_LOG_ERROR("ThreadIdentifier %u was unable to be joined.\n", threadID); 229 230 MutexLocker locker(threadMapMutex()); 231 PthreadState* state = threadMap().get(threadID); 232 ASSERT(state); 233 ASSERT(state->joinableState() == PthreadState::Joinable); 234 235 // The thread has already exited, so clean up after it. 236 if (state->hasExited()) 237 threadMap().remove(threadID); 238 // 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. 239 else 240 state->didJoin(); 241 242 return joinResult; 243 } 244 245 void detachThread(ThreadIdentifier threadID) 246 { 247 ASSERT(threadID); 248 249 MutexLocker locker(threadMapMutex()); 250 pthread_t pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID); 251 ASSERT(pthreadHandle); 252 253 int detachResult = pthread_detach(pthreadHandle); 254 if (detachResult) 255 WTF_LOG_ERROR("ThreadIdentifier %u was unable to be detached\n", threadID); 256 257 PthreadState* state = threadMap().get(threadID); 258 ASSERT(state); 259 if (state->hasExited()) 260 threadMap().remove(threadID); 261 else 262 threadMap().get(threadID)->didBecomeDetached(); 263 } 264 265 void threadDidExit(ThreadIdentifier threadID) 266 { 267 MutexLocker locker(threadMapMutex()); 268 PthreadState* state = threadMap().get(threadID); 269 ASSERT(state); 270 271 state->didExit(); 272 273 if (state->joinableState() != PthreadState::Joinable) 274 threadMap().remove(threadID); 275 } 276 277 void yield() 278 { 279 sched_yield(); 280 } 281 282 ThreadIdentifier currentThread() 283 { 284 ThreadIdentifier id = ThreadIdentifierData::identifier(); 285 if (id) 286 return id; 287 288 // Not a WTF-created thread, ThreadIdentifier is not established yet. 289 id = establishIdentifierForPthreadHandle(pthread_self()); 290 ThreadIdentifierData::initialize(id); 291 return id; 292 } 293 294 Mutex::Mutex() 295 { 296 pthread_mutexattr_t attr; 297 pthread_mutexattr_init(&attr); 298 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); 299 300 int result = pthread_mutex_init(&m_mutex, &attr); 301 ASSERT_UNUSED(result, !result); 302 303 pthread_mutexattr_destroy(&attr); 304 } 305 306 Mutex::~Mutex() 307 { 308 int result = pthread_mutex_destroy(&m_mutex); 309 ASSERT_UNUSED(result, !result); 310 } 311 312 void Mutex::lock() 313 { 314 int result = pthread_mutex_lock(&m_mutex); 315 ASSERT_UNUSED(result, !result); 316 } 317 318 bool Mutex::tryLock() 319 { 320 int result = pthread_mutex_trylock(&m_mutex); 321 322 if (result == 0) 323 return true; 324 if (result == EBUSY) 325 return false; 326 327 ASSERT_NOT_REACHED(); 328 return false; 329 } 330 331 void Mutex::unlock() 332 { 333 int result = pthread_mutex_unlock(&m_mutex); 334 ASSERT_UNUSED(result, !result); 335 } 336 337 ThreadCondition::ThreadCondition() 338 { 339 pthread_cond_init(&m_condition, NULL); 340 } 341 342 ThreadCondition::~ThreadCondition() 343 { 344 pthread_cond_destroy(&m_condition); 345 } 346 347 void ThreadCondition::wait(Mutex& mutex) 348 { 349 int result = pthread_cond_wait(&m_condition, &mutex.impl()); 350 ASSERT_UNUSED(result, !result); 351 } 352 353 bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime) 354 { 355 if (absoluteTime < currentTime()) 356 return false; 357 358 if (absoluteTime > INT_MAX) { 359 wait(mutex); 360 return true; 361 } 362 363 int timeSeconds = static_cast<int>(absoluteTime); 364 int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9); 365 366 timespec targetTime; 367 targetTime.tv_sec = timeSeconds; 368 targetTime.tv_nsec = timeNanoseconds; 369 370 return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0; 371 } 372 373 void ThreadCondition::signal() 374 { 375 int result = pthread_cond_signal(&m_condition); 376 ASSERT_UNUSED(result, !result); 377 } 378 379 void ThreadCondition::broadcast() 380 { 381 int result = pthread_cond_broadcast(&m_condition); 382 ASSERT_UNUSED(result, !result); 383 } 384 385 } // namespace WTF 386 387 #endif // USE(PTHREADS) 388