| 1 | /* | 
| 2 |  * Copyright (C) 2007, 2008 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 |  * 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(ANDROID) && !PLATFORM(QT) | 
| 75 | #include <cutils/atomic.h> | 
| 76 | #elif OS(QNX) | 
| 77 | #include <atomic.h> | 
| 78 | #endif | 
| 79 |  | 
| 80 | #if USE(PTHREADS) | 
| 81 | #include <pthread.h> | 
| 82 | #elif PLATFORM(GTK) | 
| 83 | #include <wtf/gtk/GOwnPtr.h> | 
| 84 | typedef struct _GMutex GMutex; | 
| 85 | typedef struct _GCond GCond; | 
| 86 | #endif | 
| 87 |  | 
| 88 | #if PLATFORM(QT) | 
| 89 | #include <qglobal.h> | 
| 90 | QT_BEGIN_NAMESPACE | 
| 91 | class QMutex; | 
| 92 | class QWaitCondition; | 
| 93 | QT_END_NAMESPACE | 
| 94 | #endif | 
| 95 |  | 
| 96 | #include <stdint.h> | 
| 97 |  | 
| 98 | // For portability, we do not use thread-safe statics natively supported by some compilers (e.g. gcc). | 
| 99 | #define AtomicallyInitializedStatic(T, name) \ | 
| 100 |     WTF::lockAtomicallyInitializedStaticMutex(); \ | 
| 101 |     static T name; \ | 
| 102 |     WTF::unlockAtomicallyInitializedStaticMutex(); | 
| 103 |  | 
| 104 | namespace WTF { | 
| 105 |  | 
| 106 | typedef uint32_t ThreadIdentifier; | 
| 107 | typedef void* (*ThreadFunction)(void* argument); | 
| 108 |  | 
| 109 | // Returns 0 if thread creation failed. | 
| 110 | // The thread name must be a literal since on some platforms it's passed in to the thread. | 
| 111 | ThreadIdentifier createThread(ThreadFunction, void*, const char* threadName); | 
| 112 |  | 
| 113 | // Internal platform-specific createThread implementation. | 
| 114 | ThreadIdentifier createThreadInternal(ThreadFunction, void*, const char* threadName); | 
| 115 |  | 
| 116 | // Called in the thread during initialization. | 
| 117 | // Helpful for platforms where the thread name must be set from within the thread. | 
| 118 | void initializeCurrentThreadInternal(const char* threadName); | 
| 119 |  | 
| 120 | ThreadIdentifier currentThread(); | 
| 121 | bool isMainThread(); | 
| 122 | int waitForThreadCompletion(ThreadIdentifier, void**); | 
| 123 | void detachThread(ThreadIdentifier); | 
| 124 |  | 
| 125 | #if USE(PTHREADS) | 
| 126 | typedef pthread_mutex_t PlatformMutex; | 
| 127 | #if HAVE(PTHREAD_RWLOCK) | 
| 128 | typedef pthread_rwlock_t PlatformReadWriteLock; | 
| 129 | #else | 
| 130 | typedef void* PlatformReadWriteLock; | 
| 131 | #endif | 
| 132 | typedef pthread_cond_t PlatformCondition; | 
| 133 | #elif PLATFORM(GTK) | 
| 134 | typedef GOwnPtr<GMutex> PlatformMutex; | 
| 135 | typedef void* PlatformReadWriteLock; // FIXME: Implement. | 
| 136 | typedef GOwnPtr<GCond> PlatformCondition; | 
| 137 | #elif PLATFORM(QT) | 
| 138 | typedef QT_PREPEND_NAMESPACE(QMutex)* PlatformMutex; | 
| 139 | typedef void* PlatformReadWriteLock; // FIXME: Implement. | 
| 140 | typedef QT_PREPEND_NAMESPACE(QWaitCondition)* PlatformCondition; | 
| 141 | #elif OS(WINDOWS) | 
| 142 | struct PlatformMutex { | 
| 143 |     CRITICAL_SECTION m_internalMutex; | 
| 144 |     size_t m_recursionCount; | 
| 145 | }; | 
| 146 | typedef void* PlatformReadWriteLock; // FIXME: Implement. | 
| 147 | struct PlatformCondition { | 
| 148 |     size_t m_waitersGone; | 
| 149 |     size_t m_waitersBlocked; | 
| 150 |     size_t m_waitersToUnblock;  | 
| 151 |     HANDLE m_blockLock; | 
| 152 |     HANDLE m_blockQueue; | 
| 153 |     HANDLE m_unblockLock; | 
| 154 |  | 
| 155 |     bool timedWait(PlatformMutex&, DWORD durationMilliseconds); | 
| 156 |     void signal(bool unblockAll); | 
| 157 | }; | 
| 158 | #else | 
| 159 | typedef void* PlatformMutex; | 
| 160 | typedef void* PlatformReadWriteLock; | 
| 161 | typedef void* PlatformCondition; | 
| 162 | #endif | 
| 163 |      | 
| 164 | class Mutex : public Noncopyable { | 
| 165 | public: | 
| 166 |     Mutex(); | 
| 167 |     ~Mutex(); | 
| 168 |  | 
| 169 |     void lock(); | 
| 170 |     bool tryLock(); | 
| 171 |     void unlock(); | 
| 172 |  | 
| 173 | public: | 
| 174 |     PlatformMutex& impl() { return m_mutex; } | 
| 175 | private: | 
| 176 |     PlatformMutex m_mutex; | 
| 177 | }; | 
| 178 |  | 
| 179 | typedef Locker<Mutex> MutexLocker; | 
| 180 |  | 
| 181 | class ReadWriteLock : public Noncopyable { | 
| 182 | public: | 
| 183 |     ReadWriteLock(); | 
| 184 |     ~ReadWriteLock(); | 
| 185 |  | 
| 186 |     void readLock(); | 
| 187 |     bool tryReadLock(); | 
| 188 |  | 
| 189 |     void writeLock(); | 
| 190 |     bool tryWriteLock(); | 
| 191 |      | 
| 192 |     void unlock(); | 
| 193 |  | 
| 194 | private: | 
| 195 |     PlatformReadWriteLock m_readWriteLock; | 
| 196 | }; | 
| 197 |  | 
| 198 | class ThreadCondition : public Noncopyable { | 
| 199 | public: | 
| 200 |     ThreadCondition(); | 
| 201 |     ~ThreadCondition(); | 
| 202 |      | 
| 203 |     void wait(Mutex& mutex); | 
| 204 |     // Returns true if the condition was signaled before absoluteTime, false if the absoluteTime was reached or is in the past. | 
| 205 |     // The absoluteTime is in seconds, starting on January 1, 1970. The time is assumed to use the same time zone as WTF::currentTime(). | 
| 206 |     bool timedWait(Mutex&, double absoluteTime); | 
| 207 |     void signal(); | 
| 208 |     void broadcast(); | 
| 209 |      | 
| 210 | private: | 
| 211 |     PlatformCondition m_condition; | 
| 212 | }; | 
| 213 |  | 
| 214 | #if OS(WINDOWS) | 
| 215 | #define WTF_USE_LOCKFREE_THREADSAFESHARED 1 | 
| 216 |  | 
| 217 | #if COMPILER(MINGW) || COMPILER(MSVC7) || OS(WINCE) | 
| 218 | inline int atomicIncrement(int* addend) { return InterlockedIncrement(reinterpret_cast<long*>(addend)); } | 
| 219 | inline int atomicDecrement(int* addend) { return InterlockedDecrement(reinterpret_cast<long*>(addend)); } | 
| 220 | #else | 
| 221 | inline int atomicIncrement(int volatile* addend) { return InterlockedIncrement(reinterpret_cast<long volatile*>(addend)); } | 
| 222 | inline int atomicDecrement(int volatile* addend) { return InterlockedDecrement(reinterpret_cast<long volatile*>(addend)); } | 
| 223 | #endif | 
| 224 |  | 
| 225 | #elif OS(ANDROID) && !PLATFORM(QT) | 
| 226 |  | 
| 227 | inline int atomicIncrement(int volatile* addend) { return android_atomic_inc(addend); } | 
| 228 | inline int atomicDecrement(int volatile* addend) { return android_atomic_dec(addend); } | 
| 229 |  | 
| 230 | #elif OS(QNX) | 
| 231 |  | 
| 232 | // component functions take and return unsigned | 
| 233 | inline int atomicIncrement(int volatile* addend) { return (int) atomic_add_value((unsigned volatile*)addend, 1); } | 
| 234 | inline int atomicDecrement(int volatile* addend) { return (int) atomic_sub_value((unsigned volatile*)addend, 1); } | 
| 235 |  | 
| 236 | #elif COMPILER(GCC) && !CPU(SPARC64) && !OS(SYMBIAN) // sizeof(_Atomic_word) != sizeof(int) on sparc64 gcc | 
| 237 | #define WTF_USE_LOCKFREE_THREADSAFESHARED 1 | 
| 238 |  | 
| 239 | inline int atomicIncrement(int volatile* addend) { return __sync_add_and_fetch(addend, 1); } | 
| 240 | inline int atomicDecrement(int volatile* addend) { return __sync_sub_and_fetch(addend, 1); } | 
| 241 |  | 
| 242 | #endif | 
| 243 |  | 
| 244 | class ThreadSafeSharedBase : public Noncopyable { | 
| 245 | public: | 
| 246 |     ThreadSafeSharedBase(int initialRefCount = 1) | 
| 247 |         : m_refCount(initialRefCount) | 
| 248 |     { | 
| 249 |     } | 
| 250 |  | 
| 251 |     void ref() | 
| 252 |     { | 
| 253 | #if USE(LOCKFREE_THREADSAFESHARED) | 
| 254 |         atomicIncrement(addend: &m_refCount); | 
| 255 | #else | 
| 256 |         MutexLocker locker(m_mutex); | 
| 257 |         ++m_refCount; | 
| 258 | #endif | 
| 259 |     } | 
| 260 |  | 
| 261 |     bool hasOneRef() | 
| 262 |     { | 
| 263 |         return refCount() == 1; | 
| 264 |     } | 
| 265 |  | 
| 266 |     int refCount() const | 
| 267 |     { | 
| 268 | #if !USE(LOCKFREE_THREADSAFESHARED) | 
| 269 |         MutexLocker locker(m_mutex); | 
| 270 | #endif | 
| 271 |         return static_cast<int const volatile &>(m_refCount); | 
| 272 |     } | 
| 273 |  | 
| 274 | protected: | 
| 275 |     // Returns whether the pointer should be freed or not. | 
| 276 |     bool derefBase() | 
| 277 |     { | 
| 278 | #if USE(LOCKFREE_THREADSAFESHARED) | 
| 279 |         if (atomicDecrement(addend: &m_refCount) <= 0) | 
| 280 |             return true; | 
| 281 | #else | 
| 282 |         int refCount; | 
| 283 |         { | 
| 284 |             MutexLocker locker(m_mutex); | 
| 285 |             --m_refCount; | 
| 286 |             refCount = m_refCount; | 
| 287 |         } | 
| 288 |         if (refCount <= 0) | 
| 289 |             return true; | 
| 290 | #endif | 
| 291 |         return false; | 
| 292 |     } | 
| 293 |  | 
| 294 | private: | 
| 295 |     template<class T> | 
| 296 |     friend class CrossThreadRefCounted; | 
| 297 |  | 
| 298 |     int m_refCount; | 
| 299 | #if !USE(LOCKFREE_THREADSAFESHARED) | 
| 300 |     mutable Mutex m_mutex; | 
| 301 | #endif | 
| 302 | }; | 
| 303 |  | 
| 304 | template<class T> class ThreadSafeShared : public ThreadSafeSharedBase { | 
| 305 | public: | 
| 306 |     ThreadSafeShared(int initialRefCount = 1) | 
| 307 |         : ThreadSafeSharedBase(initialRefCount) | 
| 308 |     { | 
| 309 |     } | 
| 310 |  | 
| 311 |     void deref() | 
| 312 |     { | 
| 313 |         if (derefBase()) | 
| 314 |             delete static_cast<T*>(this); | 
| 315 |     } | 
| 316 | }; | 
| 317 |  | 
| 318 | // This function must be called from the main thread. It is safe to call it repeatedly. | 
| 319 | // 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. | 
| 320 | void initializeThreading(); | 
| 321 |  | 
| 322 | void lockAtomicallyInitializedStaticMutex(); | 
| 323 | void unlockAtomicallyInitializedStaticMutex(); | 
| 324 |  | 
| 325 | } // namespace WTF | 
| 326 |  | 
| 327 | using WTF::Mutex; | 
| 328 | using WTF::MutexLocker; | 
| 329 | using WTF::ThreadCondition; | 
| 330 | using WTF::ThreadIdentifier; | 
| 331 | using WTF::ThreadSafeShared; | 
| 332 |  | 
| 333 | #if USE(LOCKFREE_THREADSAFESHARED) | 
| 334 | using WTF::atomicDecrement; | 
| 335 | using WTF::atomicIncrement; | 
| 336 | #endif | 
| 337 |  | 
| 338 | using WTF::createThread; | 
| 339 | using WTF::currentThread; | 
| 340 | using WTF::isMainThread; | 
| 341 | using WTF::detachThread; | 
| 342 | using WTF::waitForThreadCompletion; | 
| 343 |  | 
| 344 | #endif // Threading_h | 
| 345 |  |