]> git.saurik.com Git - apple/javascriptcore.git/blame - wtf/Threading.h
JavaScriptCore-584.tar.gz
[apple/javascriptcore.git] / wtf / Threading.h
CommitLineData
9dae56ea
A
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
f9bf01c6
A
62#include "Platform.h"
63
64#if OS(WINCE)
9dae56ea
A
65#include <windows.h>
66#endif
67
68#include <wtf/Assertions.h>
69#include <wtf/Locker.h>
70#include <wtf/Noncopyable.h>
71
f9bf01c6 72#if OS(WINDOWS) && !OS(WINCE)
9dae56ea 73#include <windows.h>
f9bf01c6 74#elif OS(DARWIN)
9dae56ea 75#include <libkern/OSAtomic.h>
f9bf01c6
A
76#elif OS(ANDROID)
77#include <cutils/atomic.h>
9dae56ea
A
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)
f9bf01c6 89#include <wtf/gtk/GOwnPtr.h>
9dae56ea
A
90typedef struct _GMutex GMutex;
91typedef struct _GCond GCond;
92#endif
93
9dae56ea
A
94#if PLATFORM(QT)
95#include <qglobal.h>
96QT_BEGIN_NAMESPACE
97class QMutex;
98class QWaitCondition;
99QT_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
110namespace WTF {
111
112typedef uint32_t ThreadIdentifier;
113typedef void* (*ThreadFunction)(void* argument);
114
ba379fdc
A
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.
9dae56ea 117ThreadIdentifier createThread(ThreadFunction, void*, const char* threadName);
ba379fdc
A
118
119// Internal platform-specific createThread implementation.
9dae56ea
A
120ThreadIdentifier createThreadInternal(ThreadFunction, void*, const char* threadName);
121
ba379fdc
A
122// Called in the thread during initialization.
123// Helpful for platforms where the thread name must be set from within the thread.
f9bf01c6 124void initializeCurrentThreadInternal(const char* threadName);
ba379fdc 125
9dae56ea
A
126ThreadIdentifier currentThread();
127bool isMainThread();
128int waitForThreadCompletion(ThreadIdentifier, void**);
129void detachThread(ThreadIdentifier);
130
131#if USE(PTHREADS)
132typedef pthread_mutex_t PlatformMutex;
f9bf01c6 133#if HAVE(PTHREAD_RWLOCK)
ba379fdc 134typedef pthread_rwlock_t PlatformReadWriteLock;
f9bf01c6
A
135#else
136typedef void* PlatformReadWriteLock;
137#endif
9dae56ea
A
138typedef pthread_cond_t PlatformCondition;
139#elif PLATFORM(GTK)
140typedef GOwnPtr<GMutex> PlatformMutex;
ba379fdc 141typedef void* PlatformReadWriteLock; // FIXME: Implement.
9dae56ea
A
142typedef GOwnPtr<GCond> PlatformCondition;
143#elif PLATFORM(QT)
144typedef QT_PREPEND_NAMESPACE(QMutex)* PlatformMutex;
ba379fdc 145typedef void* PlatformReadWriteLock; // FIXME: Implement.
9dae56ea 146typedef QT_PREPEND_NAMESPACE(QWaitCondition)* PlatformCondition;
f9bf01c6 147#elif OS(WINDOWS)
9dae56ea
A
148struct PlatformMutex {
149 CRITICAL_SECTION m_internalMutex;
150 size_t m_recursionCount;
151};
ba379fdc 152typedef void* PlatformReadWriteLock; // FIXME: Implement.
9dae56ea
A
153struct 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
165typedef void* PlatformMutex;
ba379fdc 166typedef void* PlatformReadWriteLock;
9dae56ea
A
167typedef void* PlatformCondition;
168#endif
169
f9bf01c6 170class Mutex : public Noncopyable {
9dae56ea
A
171public:
172 Mutex();
173 ~Mutex();
174
175 void lock();
176 bool tryLock();
177 void unlock();
178
179public:
180 PlatformMutex& impl() { return m_mutex; }
181private:
182 PlatformMutex m_mutex;
183};
184
185typedef Locker<Mutex> MutexLocker;
186
f9bf01c6 187class ReadWriteLock : public Noncopyable {
ba379fdc
A
188public:
189 ReadWriteLock();
190 ~ReadWriteLock();
191
192 void readLock();
193 bool tryReadLock();
194
195 void writeLock();
196 bool tryWriteLock();
197
198 void unlock();
199
200private:
201 PlatformReadWriteLock m_readWriteLock;
202};
203
f9bf01c6 204class ThreadCondition : public Noncopyable {
9dae56ea
A
205public:
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
216private:
217 PlatformCondition m_condition;
218};
219
f9bf01c6 220#if OS(WINDOWS)
9dae56ea
A
221#define WTF_USE_LOCKFREE_THREADSAFESHARED 1
222
f9bf01c6
A
223#if COMPILER(MINGW) || COMPILER(MSVC7) || OS(WINCE)
224inline int atomicIncrement(int* addend) { return InterlockedIncrement(reinterpret_cast<long*>(addend)); }
9dae56ea
A
225inline int atomicDecrement(int* addend) { return InterlockedDecrement(reinterpret_cast<long*>(addend)); }
226#else
f9bf01c6 227inline int atomicIncrement(int volatile* addend) { return InterlockedIncrement(reinterpret_cast<long volatile*>(addend)); }
9dae56ea
A
228inline int atomicDecrement(int volatile* addend) { return InterlockedDecrement(reinterpret_cast<long volatile*>(addend)); }
229#endif
230
f9bf01c6 231#elif OS(DARWIN)
9dae56ea
A
232#define WTF_USE_LOCKFREE_THREADSAFESHARED 1
233
f9bf01c6 234inline int atomicIncrement(int volatile* addend) { return OSAtomicIncrement32Barrier(const_cast<int*>(addend)); }
9dae56ea
A
235inline int atomicDecrement(int volatile* addend) { return OSAtomicDecrement32Barrier(const_cast<int*>(addend)); }
236
f9bf01c6
A
237#elif OS(ANDROID)
238
239inline int atomicIncrement(int volatile* addend) { return android_atomic_inc(addend); }
240inline 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
9dae56ea
A
243#define WTF_USE_LOCKFREE_THREADSAFESHARED 1
244
f9bf01c6 245inline int atomicIncrement(int volatile* addend) { return __gnu_cxx::__exchange_and_add(addend, 1) + 1; }
9dae56ea
A
246inline int atomicDecrement(int volatile* addend) { return __gnu_cxx::__exchange_and_add(addend, -1) - 1; }
247
248#endif
249
f9bf01c6 250class ThreadSafeSharedBase : public Noncopyable {
9dae56ea 251public:
ba379fdc 252 ThreadSafeSharedBase(int initialRefCount = 1)
9dae56ea
A
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
9dae56ea
A
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
ba379fdc
A
280protected:
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
9dae56ea 300private:
ba379fdc
A
301 template<class T>
302 friend class CrossThreadRefCounted;
303
9dae56ea
A
304 int m_refCount;
305#if !USE(LOCKFREE_THREADSAFESHARED)
306 mutable Mutex m_mutex;
307#endif
308};
309
ba379fdc
A
310template<class T> class ThreadSafeShared : public ThreadSafeSharedBase {
311public:
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
9dae56ea
A
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.
326void initializeThreading();
327
9dae56ea
A
328void lockAtomicallyInitializedStaticMutex();
329void unlockAtomicallyInitializedStaticMutex();
330
331} // namespace WTF
332
333using WTF::Mutex;
334using WTF::MutexLocker;
335using WTF::ThreadCondition;
336using WTF::ThreadIdentifier;
337using WTF::ThreadSafeShared;
338
f9bf01c6
A
339#if USE(LOCKFREE_THREADSAFESHARED)
340using WTF::atomicDecrement;
341using WTF::atomicIncrement;
342#endif
343
9dae56ea
A
344using WTF::createThread;
345using WTF::currentThread;
346using WTF::isMainThread;
347using WTF::detachThread;
348using WTF::waitForThreadCompletion;
349
350#endif // Threading_h