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 PLATFORM(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 PLATFORM(WIN_OS) && !PLATFORM(WINCE)
73 #include <windows.h>
74 #elif PLATFORM(DARWIN)
75 #include <libkern/OSAtomic.h>
76 #elif defined 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/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 setThreadNameInternal(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 PLATFORM(WIN_OS)
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:
impl()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 PLATFORM(WIN_OS)
221 #define WTF_USE_LOCKFREE_THREADSAFESHARED 1
222
223 #if COMPILER(MINGW) || COMPILER(MSVC7) || PLATFORM(WINCE)
atomicIncrement(int * addend)224 inline void atomicIncrement(int* addend) { InterlockedIncrement(reinterpret_cast<long*>(addend)); }
atomicDecrement(int * addend)225 inline int atomicDecrement(int* addend) { return InterlockedDecrement(reinterpret_cast<long*>(addend)); }
226 #else
atomicIncrement(int volatile * addend)227 inline void atomicIncrement(int volatile* addend) { InterlockedIncrement(reinterpret_cast<long volatile*>(addend)); }
atomicDecrement(int volatile * addend)228 inline int atomicDecrement(int volatile* addend) { return InterlockedDecrement(reinterpret_cast<long volatile*>(addend)); }
229 #endif
230
231 #elif PLATFORM(DARWIN)
232 #define WTF_USE_LOCKFREE_THREADSAFESHARED 1
233
atomicIncrement(int volatile * addend)234 inline void atomicIncrement(int volatile* addend) { OSAtomicIncrement32Barrier(const_cast<int*>(addend)); }
atomicDecrement(int volatile * addend)235 inline int atomicDecrement(int volatile* addend) { return OSAtomicDecrement32Barrier(const_cast<int*>(addend)); }
236
237 #elif defined ANDROID
238
atomicIncrement(int volatile * addend)239 inline void atomicIncrement(int volatile* addend) { android_atomic_inc(addend); }
atomicDecrement(int volatile * addend)240 inline int atomicDecrement(int volatile* addend) { return android_atomic_dec(addend); }
241
242 #elif COMPILER(GCC)
243 #define WTF_USE_LOCKFREE_THREADSAFESHARED 1
244
atomicIncrement(int volatile * addend)245 inline void atomicIncrement(int volatile* addend) { __gnu_cxx::__atomic_add(addend, 1); }
atomicDecrement(int volatile * addend)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)
m_refCount(initialRefCount)253 : m_refCount(initialRefCount)
254 {
255 }
256
ref()257 void ref()
258 {
259 #if USE(LOCKFREE_THREADSAFESHARED)
260 atomicIncrement(&m_refCount);
261 #else
262 #if defined ANDROID // avoid constructing a class to avoid two mystery crashes
263 m_mutex.lock();
264 #else
265 MutexLocker locker(m_mutex);
266 #endif
267 ++m_refCount;
268 #if defined ANDROID
269 m_mutex.unlock();
270 #endif
271 #endif
272 }
273
hasOneRef()274 bool hasOneRef()
275 {
276 return refCount() == 1;
277 }
278
refCount()279 int refCount() const
280 {
281 #if !USE(LOCKFREE_THREADSAFESHARED)
282 MutexLocker locker(m_mutex);
283 #endif
284 return static_cast<int const volatile &>(m_refCount);
285 }
286
287 protected:
288 // Returns whether the pointer should be freed or not.
derefBase()289 bool derefBase()
290 {
291 #if USE(LOCKFREE_THREADSAFESHARED)
292 if (atomicDecrement(&m_refCount) <= 0)
293 return true;
294 #else
295 int refCount;
296 {
297 #if defined ANDROID // avoid constructing a class to avoid two mystery crashes
298 m_mutex.lock();
299 #else
300 MutexLocker locker(m_mutex);
301 #endif
302 --m_refCount;
303 refCount = m_refCount;
304 #if defined ANDROID
305 m_mutex.unlock();
306 #endif
307 }
308 if (refCount <= 0)
309 return true;
310 #endif
311 return false;
312 }
313
314 private:
315 template<class T>
316 friend class CrossThreadRefCounted;
317
318 int m_refCount;
319 #if !USE(LOCKFREE_THREADSAFESHARED)
320 mutable Mutex m_mutex;
321 #endif
322 };
323
324 template<class T> class ThreadSafeShared : public ThreadSafeSharedBase {
325 public:
326 ThreadSafeShared(int initialRefCount = 1)
ThreadSafeSharedBase(initialRefCount)327 : ThreadSafeSharedBase(initialRefCount)
328 {
329 }
330
deref()331 void deref()
332 {
333 if (derefBase())
334 delete static_cast<T*>(this);
335 }
336 };
337
338 // This function must be called from the main thread. It is safe to call it repeatedly.
339 // 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.
340 void initializeThreading();
341
342 void lockAtomicallyInitializedStaticMutex();
343 void unlockAtomicallyInitializedStaticMutex();
344
345 } // namespace WTF
346
347 using WTF::Mutex;
348 using WTF::MutexLocker;
349 using WTF::ThreadCondition;
350 using WTF::ThreadIdentifier;
351 using WTF::ThreadSafeShared;
352
353 using WTF::createThread;
354 using WTF::currentThread;
355 using WTF::isMainThread;
356 using WTF::detachThread;
357 using WTF::waitForThreadCompletion;
358
359 #endif // Threading_h
360