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