Home | History | Annotate | Download | only in wtf
      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