1 /* 2 * Copyright (C) 2007, 2008 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 * Note: The implementations of InterlockedIncrement and InterlockedDecrement are based 31 * on atomic_increment and atomic_exchange_and_add from the Boost C++ Library. The license 32 * is virtually identical to the Apple license above but is included here for completeness. 33 * 34 * Boost Software License - Version 1.0 - August 17th, 2003 35 * 36 * Permission is hereby granted, free of charge, to any person or organization 37 * obtaining a copy of the software and accompanying documentation covered by 38 * this license (the "Software") to use, reproduce, display, distribute, 39 * execute, and transmit the Software, and to prepare derivative works of the 40 * Software, and to permit third-parties to whom the Software is furnished to 41 * do so, all subject to the following: 42 * 43 * The copyright notices in the Software and this entire statement, including 44 * the above license grant, this restriction and the following disclaimer, 45 * must be included in all copies of the Software, in whole or in part, and 46 * all derivative works of the Software, unless such copies or derivative 47 * works are solely in the form of machine-executable object code generated by 48 * a source language processor. 49 * 50 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 51 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 52 * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 53 * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 54 * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 55 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 56 * DEALINGS IN THE SOFTWARE. 57 */ 58 59 #ifndef Threading_h 60 #define Threading_h 61 62 #include "Platform.h" 63 64 #if OS(WINCE) 65 #include <windows.h> 66 #endif 67 68 #include <wtf/Assertions.h> 69 #include <wtf/Locker.h> 70 #include <wtf/Noncopyable.h> 71 72 #if OS(WINDOWS) && !OS(WINCE) 73 #include <windows.h> 74 #elif OS(DARWIN) 75 #include <libkern/OSAtomic.h> 76 #elif OS(ANDROID) 77 #include <cutils/atomic.h> 78 #elif COMPILER(GCC) 79 #if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)) 80 #include <ext/atomicity.h> 81 #else 82 #include <bits/atomicity.h> 83 #endif 84 #endif 85 86 #if USE(PTHREADS) 87 #include <pthread.h> 88 #elif PLATFORM(GTK) 89 #include <wtf/gtk/GOwnPtr.h> 90 typedef struct _GMutex GMutex; 91 typedef struct _GCond GCond; 92 #endif 93 94 #if PLATFORM(QT) 95 #include <qglobal.h> 96 QT_BEGIN_NAMESPACE 97 class QMutex; 98 class QWaitCondition; 99 QT_END_NAMESPACE 100 #endif 101 102 #include <stdint.h> 103 104 // For portability, we do not use thread-safe statics natively supported by some compilers (e.g. gcc). 105 #define AtomicallyInitializedStatic(T, name) \ 106 WTF::lockAtomicallyInitializedStaticMutex(); \ 107 static T name; \ 108 WTF::unlockAtomicallyInitializedStaticMutex(); 109 110 namespace WTF { 111 112 typedef uint32_t ThreadIdentifier; 113 typedef void* (*ThreadFunction)(void* argument); 114 115 // Returns 0 if thread creation failed. 116 // The thread name must be a literal since on some platforms it's passed in to the thread. 117 ThreadIdentifier createThread(ThreadFunction, void*, const char* threadName); 118 119 // Internal platform-specific createThread implementation. 120 ThreadIdentifier createThreadInternal(ThreadFunction, void*, const char* threadName); 121 122 // Called in the thread during initialization. 123 // Helpful for platforms where the thread name must be set from within the thread. 124 void initializeCurrentThreadInternal(const char* threadName); 125 126 ThreadIdentifier currentThread(); 127 bool isMainThread(); 128 int waitForThreadCompletion(ThreadIdentifier, void**); 129 void detachThread(ThreadIdentifier); 130 131 #if USE(PTHREADS) 132 typedef pthread_mutex_t PlatformMutex; 133 #if HAVE(PTHREAD_RWLOCK) 134 typedef pthread_rwlock_t PlatformReadWriteLock; 135 #else 136 typedef void* PlatformReadWriteLock; 137 #endif 138 typedef pthread_cond_t PlatformCondition; 139 #elif PLATFORM(GTK) 140 typedef GOwnPtr<GMutex> PlatformMutex; 141 typedef void* PlatformReadWriteLock; // FIXME: Implement. 142 typedef GOwnPtr<GCond> PlatformCondition; 143 #elif PLATFORM(QT) 144 typedef QT_PREPEND_NAMESPACE(QMutex)* PlatformMutex; 145 typedef void* PlatformReadWriteLock; // FIXME: Implement. 146 typedef QT_PREPEND_NAMESPACE(QWaitCondition)* PlatformCondition; 147 #elif OS(WINDOWS) 148 struct PlatformMutex { 149 CRITICAL_SECTION m_internalMutex; 150 size_t m_recursionCount; 151 }; 152 typedef void* PlatformReadWriteLock; // FIXME: Implement. 153 struct PlatformCondition { 154 size_t m_waitersGone; 155 size_t m_waitersBlocked; 156 size_t m_waitersToUnblock; 157 HANDLE m_blockLock; 158 HANDLE m_blockQueue; 159 HANDLE m_unblockLock; 160 161 bool timedWait(PlatformMutex&, DWORD durationMilliseconds); 162 void signal(bool unblockAll); 163 }; 164 #else 165 typedef void* PlatformMutex; 166 typedef void* PlatformReadWriteLock; 167 typedef void* PlatformCondition; 168 #endif 169 170 class Mutex : public Noncopyable { 171 public: 172 Mutex(); 173 ~Mutex(); 174 175 void lock(); 176 bool tryLock(); 177 void unlock(); 178 179 public: 180 PlatformMutex& impl() { return m_mutex; } 181 private: 182 PlatformMutex m_mutex; 183 }; 184 185 typedef Locker<Mutex> MutexLocker; 186 187 class ReadWriteLock : public Noncopyable { 188 public: 189 ReadWriteLock(); 190 ~ReadWriteLock(); 191 192 void readLock(); 193 bool tryReadLock(); 194 195 void writeLock(); 196 bool tryWriteLock(); 197 198 void unlock(); 199 200 private: 201 PlatformReadWriteLock m_readWriteLock; 202 }; 203 204 class ThreadCondition : public Noncopyable { 205 public: 206 ThreadCondition(); 207 ~ThreadCondition(); 208 209 void wait(Mutex& mutex); 210 // Returns true if the condition was signaled before absoluteTime, false if the absoluteTime was reached or is in the past. 211 // The absoluteTime is in seconds, starting on January 1, 1970. The time is assumed to use the same time zone as WTF::currentTime(). 212 bool timedWait(Mutex&, double absoluteTime); 213 void signal(); 214 void broadcast(); 215 216 private: 217 PlatformCondition m_condition; 218 }; 219 220 #if OS(WINDOWS) 221 #define WTF_USE_LOCKFREE_THREADSAFESHARED 1 222 223 #if COMPILER(MINGW) || COMPILER(MSVC7) || OS(WINCE) 224 inline int atomicIncrement(int* addend) { return InterlockedIncrement(reinterpret_cast<long*>(addend)); } 225 inline int atomicDecrement(int* addend) { return InterlockedDecrement(reinterpret_cast<long*>(addend)); } 226 #else 227 inline int atomicIncrement(int volatile* addend) { return InterlockedIncrement(reinterpret_cast<long volatile*>(addend)); } 228 inline int atomicDecrement(int volatile* addend) { return InterlockedDecrement(reinterpret_cast<long volatile*>(addend)); } 229 #endif 230 231 #elif OS(DARWIN) 232 #define WTF_USE_LOCKFREE_THREADSAFESHARED 1 233 234 inline int atomicIncrement(int volatile* addend) { return OSAtomicIncrement32Barrier(const_cast<int*>(addend)); } 235 inline int atomicDecrement(int volatile* addend) { return OSAtomicDecrement32Barrier(const_cast<int*>(addend)); } 236 237 #elif OS(ANDROID) 238 239 inline int atomicIncrement(int volatile* addend) { return android_atomic_inc(addend); } 240 inline int atomicDecrement(int volatile* addend) { return android_atomic_dec(addend); } 241 242 #elif COMPILER(GCC) && !CPU(SPARC64) // sizeof(_Atomic_word) != sizeof(int) on sparc64 gcc 243 #define WTF_USE_LOCKFREE_THREADSAFESHARED 1 244 245 inline int atomicIncrement(int volatile* addend) { return __gnu_cxx::__exchange_and_add(addend, 1) + 1; } 246 inline int atomicDecrement(int volatile* addend) { return __gnu_cxx::__exchange_and_add(addend, -1) - 1; } 247 248 #endif 249 250 class ThreadSafeSharedBase : public Noncopyable { 251 public: 252 ThreadSafeSharedBase(int initialRefCount = 1) 253 : m_refCount(initialRefCount) 254 { 255 } 256 257 void ref() 258 { 259 #if USE(LOCKFREE_THREADSAFESHARED) 260 atomicIncrement(&m_refCount); 261 #else 262 MutexLocker locker(m_mutex); 263 ++m_refCount; 264 #endif 265 } 266 267 bool hasOneRef() 268 { 269 return refCount() == 1; 270 } 271 272 int refCount() const 273 { 274 #if !USE(LOCKFREE_THREADSAFESHARED) 275 MutexLocker locker(m_mutex); 276 #endif 277 return static_cast<int const volatile &>(m_refCount); 278 } 279 280 protected: 281 // Returns whether the pointer should be freed or not. 282 bool derefBase() 283 { 284 #if USE(LOCKFREE_THREADSAFESHARED) 285 if (atomicDecrement(&m_refCount) <= 0) 286 return true; 287 #else 288 int refCount; 289 { 290 MutexLocker locker(m_mutex); 291 --m_refCount; 292 refCount = m_refCount; 293 } 294 if (refCount <= 0) 295 return true; 296 #endif 297 return false; 298 } 299 300 private: 301 template<class T> 302 friend class CrossThreadRefCounted; 303 304 int m_refCount; 305 #if !USE(LOCKFREE_THREADSAFESHARED) 306 mutable Mutex m_mutex; 307 #endif 308 }; 309 310 template<class T> class ThreadSafeShared : public ThreadSafeSharedBase { 311 public: 312 ThreadSafeShared(int initialRefCount = 1) 313 : ThreadSafeSharedBase(initialRefCount) 314 { 315 } 316 317 void deref() 318 { 319 if (derefBase()) 320 delete static_cast<T*>(this); 321 } 322 }; 323 324 // This function must be called from the main thread. It is safe to call it repeatedly. 325 // Darwin is an exception to this rule: it is OK to call it from any thread, the only requirement is that the calls are not reentrant. 326 void initializeThreading(); 327 328 void lockAtomicallyInitializedStaticMutex(); 329 void unlockAtomicallyInitializedStaticMutex(); 330 331 } // namespace WTF 332 333 using WTF::Mutex; 334 using WTF::MutexLocker; 335 using WTF::ThreadCondition; 336 using WTF::ThreadIdentifier; 337 using WTF::ThreadSafeShared; 338 339 #if USE(LOCKFREE_THREADSAFESHARED) 340 using WTF::atomicDecrement; 341 using WTF::atomicIncrement; 342 #endif 343 344 using WTF::createThread; 345 using WTF::currentThread; 346 using WTF::isMainThread; 347 using WTF::detachThread; 348 using WTF::waitForThreadCompletion; 349 350 #endif // Threading_h 351