123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473 |
- /*
- * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
- * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
- * Copyright (C) 2011 Research In Motion Limited. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include "config.h"
- #include "Threading.h"
- #if USE(PTHREADS)
- #include "CurrentTime.h"
- #include "DateMath.h"
- #include "dtoa.h"
- #include "dtoa/cached-powers.h"
- #include "HashMap.h"
- #include "RandomNumberSeed.h"
- #include "StackStats.h"
- #include "StdLibExtras.h"
- #include "ThreadFunctionInvocation.h"
- #include "ThreadIdentifierDataPthreads.h"
- #include "ThreadSpecific.h"
- #include <wtf/OwnPtr.h>
- #include <wtf/PassOwnPtr.h>
- #include <wtf/WTFThreadData.h>
- #include <errno.h>
- #if !COMPILER(MSVC)
- #include <limits.h>
- #include <sched.h>
- #include <sys/time.h>
- #endif
- #if OS(MAC_OS_X)
- #include <objc/objc-auto.h>
- #endif
- #if OS(ORBIS)
- #include <manx/System.h>
- #include <pthread_np.h>
- #endif
- namespace WTF {
- class PthreadState {
- WTF_MAKE_FAST_ALLOCATED;
- public:
- enum JoinableState {
- Joinable, // The default thread state. The thread can be joined on.
- Joined, // Somebody waited on this thread to exit and this thread finally exited. This state is here because there can be a
- // period of time between when the thread exits (which causes pthread_join to return and the remainder of waitOnThreadCompletion to run)
- // and when threadDidExit is called. We need threadDidExit to take charge and delete the thread data since there's
- // nobody else to pick up the slack in this case (since waitOnThreadCompletion has already returned).
- 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.
- };
- // Currently all threads created by WTF start out as joinable.
- PthreadState(pthread_t handle)
- : m_joinableState(Joinable)
- , m_didExit(false)
- , m_pthreadHandle(handle)
- {
- }
- JoinableState joinableState() { return m_joinableState; }
- pthread_t pthreadHandle() { return m_pthreadHandle; }
- void didBecomeDetached() { m_joinableState = Detached; }
- void didExit() { m_didExit = true; }
- void didJoin() { m_joinableState = Joined; }
- bool hasExited() { return m_didExit; }
- private:
- JoinableState m_joinableState;
- bool m_didExit;
- pthread_t m_pthreadHandle;
- };
- typedef HashMap<ThreadIdentifier, OwnPtr<PthreadState> > ThreadMap;
- static Mutex* atomicallyInitializedStaticMutex;
- void unsafeThreadWasDetached(ThreadIdentifier);
- void threadDidExit(ThreadIdentifier);
- void threadWasJoined(ThreadIdentifier);
- static Mutex& threadMapMutex()
- {
- DEFINE_STATIC_LOCAL(Mutex, mutex, ());
- return mutex;
- }
- #if OS(QNX) && CPU(ARM_THUMB2)
- static void enableIEEE754Denormal()
- {
- // Clear the ARM_VFP_FPSCR_FZ flag in FPSCR.
- unsigned fpscr;
- asm volatile("vmrs %0, fpscr" : "=r"(fpscr));
- fpscr &= ~0x01000000u;
- asm volatile("vmsr fpscr, %0" : : "r"(fpscr));
- }
- #endif
- void initializeThreading()
- {
- if (atomicallyInitializedStaticMutex)
- return;
- #if OS(QNX) && CPU(ARM_THUMB2)
- enableIEEE754Denormal();
- #endif
- WTF::double_conversion::initialize();
- // StringImpl::empty() does not construct its static string in a threadsafe fashion,
- // so ensure it has been initialized from here.
- StringImpl::empty();
- atomicallyInitializedStaticMutex = new Mutex;
- threadMapMutex();
- initializeRandomNumberGenerator();
- ThreadIdentifierData::initializeOnce();
- StackStats::initialize();
- wtfThreadData();
- s_dtoaP5Mutex = new Mutex;
- initializeDates();
- }
- void lockAtomicallyInitializedStaticMutex()
- {
- ASSERT(atomicallyInitializedStaticMutex);
- atomicallyInitializedStaticMutex->lock();
- }
- void unlockAtomicallyInitializedStaticMutex()
- {
- atomicallyInitializedStaticMutex->unlock();
- }
- static ThreadMap& threadMap()
- {
- DEFINE_STATIC_LOCAL(ThreadMap, map, ());
- return map;
- }
- static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle)
- {
- MutexLocker locker(threadMapMutex());
- ThreadMap::iterator i = threadMap().begin();
- for (; i != threadMap().end(); ++i) {
- if (pthread_equal(i->value->pthreadHandle(), pthreadHandle) && !i->value->hasExited())
- return i->key;
- }
- return 0;
- }
- static ThreadIdentifier establishIdentifierForPthreadHandle(const pthread_t& pthreadHandle)
- {
- ASSERT(!identifierByPthreadHandle(pthreadHandle));
- MutexLocker locker(threadMapMutex());
- static ThreadIdentifier identifierCount = 1;
- threadMap().add(identifierCount, adoptPtr(new PthreadState(pthreadHandle)));
- return identifierCount++;
- }
- static pthread_t pthreadHandleForIdentifierWithLockAlreadyHeld(ThreadIdentifier id)
- {
- return threadMap().get(id)->pthreadHandle();
- }
- static void* wtfThreadEntryPoint(void* param)
- {
- // Balanced by .leakPtr() in createThreadInternal.
- OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(static_cast<ThreadFunctionInvocation*>(param));
- invocation->function(invocation->data);
- return 0;
- }
- #if OS(ORBIS)
- static size_t stackSize(const char* name)
- {
- if (!strcmp(name, "WebCore: Worker"))
- return 512 * 1024;
- return 64 * 1024;
- }
- #endif
- ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char* name)
- {
- OwnPtr<ThreadFunctionInvocation> invocation = adoptPtr(new ThreadFunctionInvocation(entryPoint, data));
- pthread_t threadHandle;
- pthread_attr_t* attr = 0;
- #if OS(ORBIS)
- pthread_attr_t aAttr;
- attr = &aAttr;
- pthread_attr_init(attr);
- pthread_attr_setstacksize(attr, stackSize(name));
- #elif OS(PSP2)
- pthread_attr_t aAttr;
- if (name) {
- attr = &aAttr;
- pthread_attr_init(attr);
- pthread_attr_setname_sce(attr, name);
- }
- #endif
- if (pthread_create(&threadHandle, attr, wtfThreadEntryPoint, invocation.get())) {
- LOG_ERROR("Failed to create pthread at entry point %p with data %p", wtfThreadEntryPoint, invocation.get());
- return 0;
- }
- #if OS(ORBIS)
- pthread_attr_destroy(attr);
- pthread_setprio(threadHandle, Manx::System::defaultThreadPriority());
- #elif OS(PSP2)
- if (attr)
- pthread_attr_destroy(attr);
- #endif
- // Balanced by adoptPtr() in wtfThreadEntryPoint.
- ThreadFunctionInvocation* leakedInvocation = invocation.leakPtr();
- UNUSED_PARAM(leakedInvocation);
- return establishIdentifierForPthreadHandle(threadHandle);
- }
- void initializeCurrentThreadInternal(const char* threadName)
- {
- #if HAVE(PTHREAD_SETNAME_NP)
- pthread_setname_np(threadName);
- #elif OS(QNX)
- pthread_setname_np(pthread_self(), threadName);
- #elif OS(ORBIS)
- pthread_set_name_np(pthread_self(), threadName);
- #else
- UNUSED_PARAM(threadName);
- #endif
- #if OS(MAC_OS_X)
- // All threads that potentially use APIs above the BSD layer must be registered with the Objective-C
- // garbage collector in case API implementations use garbage-collected memory.
- objc_registerThreadWithCollector();
- #endif
- #if OS(QNX) && CPU(ARM_THUMB2)
- enableIEEE754Denormal();
- #endif
- ThreadIdentifier id = identifierByPthreadHandle(pthread_self());
- ASSERT(id);
- ThreadIdentifierData::initialize(id);
- }
- int waitForThreadCompletion(ThreadIdentifier threadID)
- {
- pthread_t pthreadHandle;
- ASSERT(threadID);
- {
- // We don't want to lock across the call to join, since that can block our thread and cause deadlock.
- MutexLocker locker(threadMapMutex());
- pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID);
- ASSERT(pthreadHandle);
- }
- int joinResult = pthread_join(pthreadHandle, 0);
- if (joinResult == EDEADLK)
- LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
- else if (joinResult)
- LOG_ERROR("ThreadIdentifier %u was unable to be joined.\n", threadID);
- MutexLocker locker(threadMapMutex());
- PthreadState* state = threadMap().get(threadID);
- ASSERT(state);
- ASSERT(state->joinableState() == PthreadState::Joinable);
- // The thread has already exited, so clean up after it.
- if (state->hasExited())
- threadMap().remove(threadID);
- // 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.
- else
- state->didJoin();
- return joinResult;
- }
- void detachThread(ThreadIdentifier threadID)
- {
- ASSERT(threadID);
- MutexLocker locker(threadMapMutex());
- pthread_t pthreadHandle = pthreadHandleForIdentifierWithLockAlreadyHeld(threadID);
- ASSERT(pthreadHandle);
- int detachResult = pthread_detach(pthreadHandle);
- if (detachResult)
- LOG_ERROR("ThreadIdentifier %u was unable to be detached\n", threadID);
- PthreadState* state = threadMap().get(threadID);
- ASSERT(state);
- if (state->hasExited())
- threadMap().remove(threadID);
- else
- threadMap().get(threadID)->didBecomeDetached();
- }
- void threadDidExit(ThreadIdentifier threadID)
- {
- MutexLocker locker(threadMapMutex());
- PthreadState* state = threadMap().get(threadID);
- ASSERT(state);
-
- state->didExit();
- if (state->joinableState() != PthreadState::Joinable)
- threadMap().remove(threadID);
- }
- void yield()
- {
- sched_yield();
- }
- ThreadIdentifier currentThread()
- {
- ThreadIdentifier id = ThreadIdentifierData::identifier();
- if (id)
- return id;
- // Not a WTF-created thread, ThreadIdentifier is not established yet.
- id = establishIdentifierForPthreadHandle(pthread_self());
- ThreadIdentifierData::initialize(id);
- return id;
- }
- Mutex::Mutex()
- {
- pthread_mutexattr_t attr;
- pthread_mutexattr_init(&attr);
- pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
- int result = pthread_mutex_init(&m_mutex, &attr);
- ASSERT_UNUSED(result, !result);
- pthread_mutexattr_destroy(&attr);
- }
- Mutex::~Mutex()
- {
- int result = pthread_mutex_destroy(&m_mutex);
- ASSERT_UNUSED(result, !result);
- }
- void Mutex::lock()
- {
- int result = pthread_mutex_lock(&m_mutex);
- ASSERT_UNUSED(result, !result);
- }
- bool Mutex::tryLock()
- {
- int result = pthread_mutex_trylock(&m_mutex);
- if (result == 0)
- return true;
- if (result == EBUSY)
- return false;
- ASSERT_NOT_REACHED();
- return false;
- }
- void Mutex::unlock()
- {
- int result = pthread_mutex_unlock(&m_mutex);
- ASSERT_UNUSED(result, !result);
- }
- #if USE(MANX_COND_INIT)
- ThreadCondition::ThreadCondition(Mutex& mutex)
- {
- int result = pthread_cond_init_sce(&m_condition, &mutex.impl(), NULL);
- ASSERT_UNUSED(result, !result);
- }
- #else
- ThreadCondition::ThreadCondition()
- {
- pthread_cond_init(&m_condition, NULL);
- }
- #endif
- ThreadCondition::~ThreadCondition()
- {
- pthread_cond_destroy(&m_condition);
- }
-
- void ThreadCondition::wait(Mutex& mutex)
- {
- int result = pthread_cond_wait(&m_condition, &mutex.impl());
- ASSERT_UNUSED(result, !result);
- }
- bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
- {
- if (absoluteTime < currentTime())
- return false;
- #if PLATFORM(MANX)
- if (absoluteTime > std::numeric_limits<time_t>::max()) {
- #else
- if (absoluteTime > INT_MAX) {
- #endif
- wait(mutex);
- return true;
- }
- #if PLATFORM(MANX)
- time_t timeSeconds = static_cast<time_t>(absoluteTime);
- long timeNanoseconds = static_cast<long>((absoluteTime - timeSeconds) * 1E9);
- #else
- int timeSeconds = static_cast<int>(absoluteTime);
- int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9);
- #endif
- timespec targetTime;
- targetTime.tv_sec = timeSeconds;
- targetTime.tv_nsec = timeNanoseconds;
- return pthread_cond_timedwait(&m_condition, &mutex.impl(), &targetTime) == 0;
- }
- void ThreadCondition::signal()
- {
- int result = pthread_cond_signal(&m_condition);
- ASSERT_UNUSED(result, !result);
- }
- void ThreadCondition::broadcast()
- {
- int result = pthread_cond_broadcast(&m_condition);
- ASSERT_UNUSED(result, !result);
- }
- } // namespace WTF
- #endif // USE(PTHREADS)
|