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 | |