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/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 67 namespace WTF { 68 69 static Mutex* atomicallyInitializedStaticMutex; 70 71 void 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 89 void lockAtomicallyInitializedStaticMutex() 90 { 91 ASSERT(atomicallyInitializedStaticMutex); 92 atomicallyInitializedStaticMutex->lock(); 93 } 94 95 void unlockAtomicallyInitializedStaticMutex() 96 { 97 atomicallyInitializedStaticMutex->unlock(); 98 } 99 100 ThreadIdentifier 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 113 MutexBase::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 128 MutexBase::~MutexBase() 129 { 130 int result = pthread_mutex_destroy(&m_mutex.m_internalMutex); 131 ASSERT_UNUSED(result, !result); 132 } 133 134 void 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 143 void 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. 158 bool 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 177 bool 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 193 ThreadCondition::ThreadCondition() 194 { 195 pthread_cond_init(&m_condition, NULL); 196 } 197 198 ThreadCondition::~ThreadCondition() 199 { 200 pthread_cond_destroy(&m_condition); 201 } 202 203 void 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 213 bool 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 238 void ThreadCondition::signal() 239 { 240 int result = pthread_cond_signal(&m_condition); 241 ASSERT_UNUSED(result, !result); 242 } 243 244 void 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