1/* 2 * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. 3 * Copyright (C) 2007 Justin Haygood (jhaygood@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/ThreadSpecific.h" 43#include "wtf/ThreadingPrimitives.h" 44#include "wtf/WTFThreadData.h" 45#include "wtf/dtoa.h" 46#include "wtf/dtoa/cached-powers.h" 47#include <errno.h> 48 49#if !COMPILER(MSVC) 50#include <limits.h> 51#include <sched.h> 52#include <sys/time.h> 53#endif 54 55#if OS(MACOSX) 56#include <objc/objc-auto.h> 57#endif 58 59#if OS(LINUX) 60#include <sys/syscall.h> 61#endif 62 63#if OS(LINUX) || OS(ANDROID) 64#include <unistd.h> 65#endif 66 67namespace WTF { 68 69static Mutex* atomicallyInitializedStaticMutex; 70 71void initializeThreading() 72{ 73 // This should only be called once. 74 ASSERT(!atomicallyInitializedStaticMutex); 75 76 // StringImpl::empty() does not construct its static string in a threadsafe fashion, 77 // so ensure it has been initialized from here. 78 StringImpl::empty(); 79 StringImpl::empty16Bit(); 80 atomicallyInitializedStaticMutex = new Mutex; 81 wtfThreadData(); 82 s_dtoaP5Mutex = new Mutex; 83 initializeDates(); 84 // Force initialization of static DoubleToStringConverter converter variable 85 // inside EcmaScriptConverter function while we are in single thread mode. 86 double_conversion::DoubleToStringConverter::EcmaScriptConverter(); 87} 88 89void lockAtomicallyInitializedStaticMutex() 90{ 91 ASSERT(atomicallyInitializedStaticMutex); 92 atomicallyInitializedStaticMutex->lock(); 93} 94 95void unlockAtomicallyInitializedStaticMutex() 96{ 97 atomicallyInitializedStaticMutex->unlock(); 98} 99 100ThreadIdentifier currentThread() 101{ 102#if OS(MACOSX) 103 return pthread_mach_thread_np(pthread_self()); 104#elif OS(LINUX) 105 return syscall(__NR_gettid); 106#elif OS(ANDROID) 107 return gettid(); 108#else 109 return reinterpret_cast<uintptr_t>(pthread_self()); 110#endif 111} 112 113MutexBase::MutexBase(bool recursive) 114{ 115 pthread_mutexattr_t attr; 116 pthread_mutexattr_init(&attr); 117 pthread_mutexattr_settype(&attr, recursive ? PTHREAD_MUTEX_RECURSIVE : PTHREAD_MUTEX_NORMAL); 118 119 int result = pthread_mutex_init(&m_mutex.m_internalMutex, &attr); 120 ASSERT_UNUSED(result, !result); 121#if ENABLE(ASSERT) 122 m_mutex.m_recursionCount = 0; 123#endif 124 125 pthread_mutexattr_destroy(&attr); 126} 127 128MutexBase::~MutexBase() 129{ 130 int result = pthread_mutex_destroy(&m_mutex.m_internalMutex); 131 ASSERT_UNUSED(result, !result); 132} 133 134void MutexBase::lock() 135{ 136 int result = pthread_mutex_lock(&m_mutex.m_internalMutex); 137 ASSERT_UNUSED(result, !result); 138#if ENABLE(ASSERT) 139 ++m_mutex.m_recursionCount; 140#endif 141} 142 143void MutexBase::unlock() 144{ 145#if ENABLE(ASSERT) 146 ASSERT(m_mutex.m_recursionCount); 147 --m_mutex.m_recursionCount; 148#endif 149 int result = pthread_mutex_unlock(&m_mutex.m_internalMutex); 150 ASSERT_UNUSED(result, !result); 151} 152 153// There is a separate tryLock implementation for the Mutex and the 154// RecursiveMutex since on Windows we need to manually check if tryLock should 155// succeed or not for the non-recursive mutex. On Linux the two implementations 156// are equal except we can assert the recursion count is always zero for the 157// non-recursive mutex. 158bool Mutex::tryLock() 159{ 160 int result = pthread_mutex_trylock(&m_mutex.m_internalMutex); 161 if (result == 0) { 162#if ENABLE(ASSERT) 163 // The Mutex class is not recursive, so the recursionCount should be 164 // zero after getting the lock. 165 ASSERT(!m_mutex.m_recursionCount); 166 ++m_mutex.m_recursionCount; 167#endif 168 return true; 169 } 170 if (result == EBUSY) 171 return false; 172 173 ASSERT_NOT_REACHED(); 174 return false; 175} 176 177bool RecursiveMutex::tryLock() 178{ 179 int result = pthread_mutex_trylock(&m_mutex.m_internalMutex); 180 if (result == 0) { 181#if ENABLE(ASSERT) 182 ++m_mutex.m_recursionCount; 183#endif 184 return true; 185 } 186 if (result == EBUSY) 187 return false; 188 189 ASSERT_NOT_REACHED(); 190 return false; 191} 192 193ThreadCondition::ThreadCondition() 194{ 195 pthread_cond_init(&m_condition, NULL); 196} 197 198ThreadCondition::~ThreadCondition() 199{ 200 pthread_cond_destroy(&m_condition); 201} 202 203void ThreadCondition::wait(MutexBase& mutex) 204{ 205 PlatformMutex& platformMutex = mutex.impl(); 206 int result = pthread_cond_wait(&m_condition, &platformMutex.m_internalMutex); 207 ASSERT_UNUSED(result, !result); 208#if ENABLE(ASSERT) 209 ++platformMutex.m_recursionCount; 210#endif 211} 212 213bool ThreadCondition::timedWait(MutexBase& mutex, double absoluteTime) 214{ 215 if (absoluteTime < currentTime()) 216 return false; 217 218 if (absoluteTime > INT_MAX) { 219 wait(mutex); 220 return true; 221 } 222 223 int timeSeconds = static_cast<int>(absoluteTime); 224 int timeNanoseconds = static_cast<int>((absoluteTime - timeSeconds) * 1E9); 225 226 timespec targetTime; 227 targetTime.tv_sec = timeSeconds; 228 targetTime.tv_nsec = timeNanoseconds; 229 230 PlatformMutex& platformMutex = mutex.impl(); 231 int result = pthread_cond_timedwait(&m_condition, &platformMutex.m_internalMutex, &targetTime); 232#if ENABLE(ASSERT) 233 ++platformMutex.m_recursionCount; 234#endif 235 return result == 0; 236} 237 238void ThreadCondition::signal() 239{ 240 int result = pthread_cond_signal(&m_condition); 241 ASSERT_UNUSED(result, !result); 242} 243 244void ThreadCondition::broadcast() 245{ 246 int result = pthread_cond_broadcast(&m_condition); 247 ASSERT_UNUSED(result, !result); 248} 249 250} // namespace WTF 251 252#endif // USE(PTHREADS) 253