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  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *
      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.
     17  *
     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.
     28  */
     29 
     30 #include "config.h"
     31 #include "Threading.h"
     32 
     33 #if USE(PTHREADS)
     34 
     35 #include "CurrentTime.h"
     36 #include "HashMap.h"
     37 #include "MainThread.h"
     38 #include "RandomNumberSeed.h"
     39 #include "StdLibExtras.h"
     40 #include "ThreadIdentifierDataPthreads.h"
     41 #include "ThreadSpecific.h"
     42 #include "UnusedParam.h"
     43 #include <errno.h>
     44 
     45 #if !COMPILER(MSVC)
     46 #include <limits.h>
     47 #include <sched.h>
     48 #include <sys/time.h>
     49 #endif
     50 
     51 #if OS(ANDROID)
     52 #include "JNIUtility.h"
     53 #include "ThreadFunctionInvocation.h"
     54 #include <wtf/OwnPtr.h>
     55 #include <wtf/PassOwnPtr.h>
     56 #endif
     57 
     58 #if OS(MAC_OS_X) && !defined(BUILDING_ON_LEOPARD)
     59 #include <objc/objc-auto.h>
     60 #endif
     61 
     62 namespace WTF {
     63 
     64 typedef HashMap<ThreadIdentifier, pthread_t> ThreadMap;
     65 
     66 static Mutex* atomicallyInitializedStaticMutex;
     67 
     68 void clearPthreadHandleForIdentifier(ThreadIdentifier);
     69 
     70 static Mutex& threadMapMutex()
     71 {
     72     DEFINE_STATIC_LOCAL(Mutex, mutex, ());
     73     return mutex;
     74 }
     75 
     76 void initializeThreading()
     77 {
     78     if (atomicallyInitializedStaticMutex)
     79         return;
     80 
     81     atomicallyInitializedStaticMutex = new Mutex;
     82     threadMapMutex();
     83     initializeRandomNumberGenerator();
     84 }
     85 
     86 void lockAtomicallyInitializedStaticMutex()
     87 {
     88     ASSERT(atomicallyInitializedStaticMutex);
     89     atomicallyInitializedStaticMutex->lock();
     90 }
     91 
     92 void unlockAtomicallyInitializedStaticMutex()
     93 {
     94     atomicallyInitializedStaticMutex->unlock();
     95 }
     96 
     97 static ThreadMap& threadMap()
     98 {
     99     DEFINE_STATIC_LOCAL(ThreadMap, map, ());
    100     return map;
    101 }
    102 
    103 static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle)
    104 {
    105     MutexLocker locker(threadMapMutex());
    106 
    107     ThreadMap::iterator i = threadMap().begin();
    108     for (; i != threadMap().end(); ++i) {
    109         if (pthread_equal(i->second, pthreadHandle))
    110             return i->first;
    111     }
    112 
    113     return 0;
    114 }
    115 
    116 static ThreadIdentifier establishIdentifierForPthreadHandle(const pthread_t& pthreadHandle)
    117 {
    118     ASSERT(!identifierByPthreadHandle(pthreadHandle));
    119 
    120     MutexLocker locker(threadMapMutex());
    121 
    122     static ThreadIdentifier identifierCount = 1;
    123 
    124     threadMap().add(identifierCount, pthreadHandle);
    125 
    126     return identifierCount++;
    127 }
    128 
    129 static pthread_t pthreadHandleForIdentifier(ThreadIdentifier id)
    130 {
    131     MutexLocker locker(threadMapMutex());
    132 
    133     return threadMap().get(id);
    134 }
    135 
    136 void clearPthreadHandleForIdentifier(ThreadIdentifier id)
    137 {
    138     MutexLocker locker(threadMapMutex());
    139 
    140     ASSERT(threadMap().contains(id));
    141 
    142     threadMap().remove(id);
    143 }
    144 
    145 #if OS(ANDROID)
    146 static void* runThreadWithRegistration(void* arg)
    147 {
    148     OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(static_cast<ThreadFunctionInvocation*>(arg));
    149     JavaVM* vm = JSC::Bindings::getJavaVM();
    150     JNIEnv* env;
    151     void* ret = 0;
    152     if (vm->AttachCurrentThread(&env, 0) == JNI_OK) {
    153         ret = invocation->function(invocation->data);
    154         vm->DetachCurrentThread();
    155     }
    156     return ret;
    157 }
    158 
    159 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
    160 {
    161     pthread_t threadHandle;
    162 
    163     // On the Android platform, threads must be registered with the VM before they run.
    164     OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(new ThreadFunctionInvocation(entryPoint, data));
    165 
    166     if (pthread_create(&threadHandle, 0, runThreadWithRegistration, invocation.get())) {
    167         LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint, data);
    168         return 0;
    169     }
    170 
    171     // The thread will take ownership of invocation.
    172     ThreadFunctionInvocation* unused = invocation.leakPtr();
    173 
    174     return establishIdentifierForPthreadHandle(threadHandle);
    175 }
    176 #else
    177 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
    178 {
    179     pthread_t threadHandle;
    180     if (pthread_create(&threadHandle, 0, entryPoint, data)) {
    181         LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint, data);
    182         return 0;
    183     }
    184 
    185     return establishIdentifierForPthreadHandle(threadHandle);
    186 }
    187 #endif
    188 
    189 void initializeCurrentThreadInternal(const char* threadName)
    190 {
    191 #if HAVE(PTHREAD_SETNAME_NP)
    192     pthread_setname_np(threadName);
    193 #else
    194     UNUSED_PARAM(threadName);
    195 #endif
    196 
    197 #if OS(MAC_OS_X) && !defined(BUILDING_ON_LEOPARD)
    198     // All threads that potentially use APIs above the BSD layer must be registered with the Objective-C
    199     // garbage collector in case API implementations use garbage-collected memory.
    200     objc_registerThreadWithCollector();
    201 #endif
    202 
    203     ThreadIdentifier id = identifierByPthreadHandle(pthread_self());
    204     ASSERT(id);
    205     ThreadIdentifierData::initialize(id);
    206 }
    207 
    208 int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
    209 {
    210     ASSERT(threadID);
    211 
    212     pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
    213     if (!pthreadHandle)
    214         return 0;
    215 
    216     int joinResult = pthread_join(pthreadHandle, result);
    217     if (joinResult == EDEADLK)
    218         LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
    219 
    220     return joinResult;
    221 }
    222 
    223 void detachThread(ThreadIdentifier threadID)
    224 {
    225     ASSERT(threadID);
    226 
    227     pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
    228     if (!pthreadHandle)
    229         return;
    230 
    231     pthread_detach(pthreadHandle);
    232 }
    233 
    234 void yield()
    235 {
    236     sched_yield();
    237 }
    238 
    239 ThreadIdentifier currentThread()
    240 {
    241     ThreadIdentifier id = ThreadIdentifierData::identifier();
    242     if (id)
    243         return id;
    244 
    245     // Not a WTF-created thread, ThreadIdentifier is not established yet.
    246     id = establishIdentifierForPthreadHandle(pthread_self());
    247     ThreadIdentifierData::initialize(id);
    248     return id;
    249 }
    250 
    251 Mutex::Mutex()
    252 {
    253     pthread_mutexattr_t attr;
    254     pthread_mutexattr_init(&attr);
    255     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
    256 
    257     pthread_mutex_init(&m_mutex, &attr);
    258 
    259     pthread_mutexattr_destroy(&attr);
    260 }
    261 
    262 Mutex::~Mutex()
    263 {
    264     pthread_mutex_destroy(&m_mutex);
    265 }
    266 
    267 void Mutex::lock()
    268 {
    269     int result = pthread_mutex_lock(&m_mutex);
    270     ASSERT_UNUSED(result, !result);
    271 }
    272 
    273 bool Mutex::tryLock()
    274 {
    275     int result = pthread_mutex_trylock(&m_mutex);
    276 
    277     if (result == 0)
    278         return true;
    279     if (result == EBUSY)
    280         return false;
    281 
    282     ASSERT_NOT_REACHED();
    283     return false;
    284 }
    285 
    286 void Mutex::unlock()
    287 {
    288     int result = pthread_mutex_unlock(&m_mutex);
    289     ASSERT_UNUSED(result, !result);
    290 }
    291 
    292 #if HAVE(PTHREAD_RWLOCK)
    293 ReadWriteLock::ReadWriteLock()
    294 {
    295     pthread_rwlock_init(&m_readWriteLock, NULL);
    296 }
    297 
    298 ReadWriteLock::~ReadWriteLock()
    299 {
    300     pthread_rwlock_destroy(&m_readWriteLock);
    301 }
    302 
    303 void ReadWriteLock::readLock()
    304 {
    305     int result = pthread_rwlock_rdlock(&m_readWriteLock);
    306     ASSERT_UNUSED(result, !result);
    307 }
    308 
    309 bool ReadWriteLock::tryReadLock()
    310 {
    311     int result = pthread_rwlock_tryrdlock(&m_readWriteLock);
    312 
    313     if (result == 0)
    314         return true;
    315     if (result == EBUSY || result == EAGAIN)
    316         return false;
    317 
    318     ASSERT_NOT_REACHED();
    319     return false;
    320 }
    321 
    322 void ReadWriteLock::writeLock()
    323 {
    324     int result = pthread_rwlock_wrlock(&m_readWriteLock);
    325     ASSERT_UNUSED(result, !result);
    326 }
    327 
    328 bool ReadWriteLock::tryWriteLock()
    329 {
    330     int result = pthread_rwlock_trywrlock(&m_readWriteLock);
    331 
    332     if (result == 0)
    333         return true;
    334     if (result == EBUSY || result == EAGAIN)
    335         return false;
    336 
    337     ASSERT_NOT_REACHED();
    338     return false;
    339 }
    340 
    341 void ReadWriteLock::unlock()
    342 {
    343     int result = pthread_rwlock_unlock(&m_readWriteLock);
    344     ASSERT_UNUSED(result, !result);
    345 }
    346 #endif  // HAVE(PTHREAD_RWLOCK)
    347 
    348 ThreadCondition::ThreadCondition()
    349 {
    350     pthread_cond_init(&m_condition, NULL);
    351 }
    352 
    353 ThreadCondition::~ThreadCondition()
    354 {
    355     pthread_cond_destroy(&m_condition);
    356 }
    357 
    358 void ThreadCondition::wait(Mutex& mutex)
    359 {
    360     int result = pthread_cond_wait(&m_condition, &mutex.impl());
    361     ASSERT_UNUSED(result, !result);
    362 }
    363 
    364 bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
    365 {
    366     if (absoluteTime < currentTime())
    367         return false;
    368 
    369     if (absoluteTime > INT_MAX) {
    370         wait(mutex);
    371         return true;
    372     }
    373 
    374     int timeSeconds = static_cast<int>(absoluteTime);
    375     int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9);
    376 
    377     timespec targetTime;
    378     targetTime.tv_sec = timeSeconds;
    379     targetTime.tv_nsec = timeNanoseconds;
    380 
    381     return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0;
    382 }
    383 
    384 void ThreadCondition::signal()
    385 {
    386     int result = pthread_cond_signal(&m_condition);
    387     ASSERT_UNUSED(result, !result);
    388 }
    389 
    390 void ThreadCondition::broadcast()
    391 {
    392     int result = pthread_cond_broadcast(&m_condition);
    393     ASSERT_UNUSED(result, !result);
    394 }
    395 
    396 } // namespace WTF
    397 
    398 #endif // USE(PTHREADS)
    399