]> git.saurik.com Git - apple/javascriptcore.git/blob - wtf/ThreadingQt.cpp
JavaScriptCore-521.tar.gz
[apple/javascriptcore.git] / wtf / ThreadingQt.cpp
1 /*
2 * Copyright (C) 2007 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 #include "config.h"
30 #include "Threading.h"
31
32 #include "CurrentTime.h"
33 #include "HashMap.h"
34 #include "MainThread.h"
35 #include "RandomNumberSeed.h"
36
37 #include <QCoreApplication>
38 #include <QMutex>
39 #include <QThread>
40 #include <QWaitCondition>
41
42 namespace WTF {
43
44 class ThreadPrivate : public QThread {
45 public:
46 ThreadPrivate(ThreadFunction entryPoint, void* data);
47 void run();
48 void* getReturnValue() { return m_returnValue; }
49 private:
50 void* m_data;
51 ThreadFunction m_entryPoint;
52 void* m_returnValue;
53 };
54
55 ThreadPrivate::ThreadPrivate(ThreadFunction entryPoint, void* data)
56 : m_data(data)
57 , m_entryPoint(entryPoint)
58 , m_returnValue(0)
59 {
60 }
61
62 void ThreadPrivate::run()
63 {
64 m_returnValue = m_entryPoint(m_data);
65 }
66
67
68 static Mutex* atomicallyInitializedStaticMutex;
69
70 static ThreadIdentifier mainThreadIdentifier;
71
72 static Mutex& threadMapMutex()
73 {
74 static Mutex mutex;
75 return mutex;
76 }
77
78 static HashMap<ThreadIdentifier, QThread*>& threadMap()
79 {
80 static HashMap<ThreadIdentifier, QThread*> map;
81 return map;
82 }
83
84 static ThreadIdentifier identifierByQthreadHandle(QThread*& thread)
85 {
86 MutexLocker locker(threadMapMutex());
87
88 HashMap<ThreadIdentifier, QThread*>::iterator i = threadMap().begin();
89 for (; i != threadMap().end(); ++i) {
90 if (i->second == thread)
91 return i->first;
92 }
93
94 return 0;
95 }
96
97 static ThreadIdentifier establishIdentifierForThread(QThread*& thread)
98 {
99 ASSERT(!identifierByQthreadHandle(thread));
100
101 MutexLocker locker(threadMapMutex());
102
103 static ThreadIdentifier identifierCount = 1;
104
105 threadMap().add(identifierCount, thread);
106
107 return identifierCount++;
108 }
109
110 static void clearThreadForIdentifier(ThreadIdentifier id)
111 {
112 MutexLocker locker(threadMapMutex());
113
114 ASSERT(threadMap().contains(id));
115
116 threadMap().remove(id);
117 }
118
119 static QThread* threadForIdentifier(ThreadIdentifier id)
120 {
121 MutexLocker locker(threadMapMutex());
122
123 return threadMap().get(id);
124 }
125
126 void initializeThreading()
127 {
128 if (!atomicallyInitializedStaticMutex) {
129 atomicallyInitializedStaticMutex = new Mutex;
130 threadMapMutex();
131 initializeRandomNumberGenerator();
132 QThread* mainThread = QCoreApplication::instance()->thread();
133 mainThreadIdentifier = identifierByQthreadHandle(mainThread);
134 if (!mainThreadIdentifier)
135 mainThreadIdentifier = establishIdentifierForThread(mainThread);
136 initializeMainThread();
137 }
138 }
139
140 void lockAtomicallyInitializedStaticMutex()
141 {
142 ASSERT(atomicallyInitializedStaticMutex);
143 atomicallyInitializedStaticMutex->lock();
144 }
145
146 void unlockAtomicallyInitializedStaticMutex()
147 {
148 atomicallyInitializedStaticMutex->unlock();
149 }
150
151 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
152 {
153 ThreadPrivate* thread = new ThreadPrivate(entryPoint, data);
154 if (!thread) {
155 LOG_ERROR("Failed to create thread at entry point %p with data %p", entryPoint, data);
156 return 0;
157 }
158 thread->start();
159
160 QThread* threadRef = static_cast<QThread*>(thread);
161
162 return establishIdentifierForThread(threadRef);
163 }
164
165 int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
166 {
167 ASSERT(threadID);
168
169 QThread* thread = threadForIdentifier(threadID);
170
171 bool res = thread->wait();
172
173 clearThreadForIdentifier(threadID);
174 if (result)
175 *result = static_cast<ThreadPrivate*>(thread)->getReturnValue();
176
177 return !res;
178 }
179
180 void detachThread(ThreadIdentifier)
181 {
182 }
183
184 ThreadIdentifier currentThread()
185 {
186 QThread* currentThread = QThread::currentThread();
187 if (ThreadIdentifier id = identifierByQthreadHandle(currentThread))
188 return id;
189 return establishIdentifierForThread(currentThread);
190 }
191
192 bool isMainThread()
193 {
194 return currentThread() == mainThreadIdentifier;
195 }
196
197 Mutex::Mutex()
198 : m_mutex(new QMutex())
199 {
200 }
201
202 Mutex::~Mutex()
203 {
204 delete m_mutex;
205 }
206
207 void Mutex::lock()
208 {
209 m_mutex->lock();
210 }
211
212 bool Mutex::tryLock()
213 {
214 return m_mutex->tryLock();
215 }
216
217 void Mutex::unlock()
218 {
219 m_mutex->unlock();
220 }
221
222 ThreadCondition::ThreadCondition()
223 : m_condition(new QWaitCondition())
224 {
225 }
226
227 ThreadCondition::~ThreadCondition()
228 {
229 delete m_condition;
230 }
231
232 void ThreadCondition::wait(Mutex& mutex)
233 {
234 m_condition->wait(mutex.impl());
235 }
236
237 bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
238 {
239 double currentTime = WTF::currentTime();
240
241 // Time is in the past - return immediately.
242 if (absoluteTime < currentTime)
243 return false;
244
245 double intervalMilliseconds = (absoluteTime - currentTime) * 1000.0;
246 // Qt defines wait for up to ULONG_MAX milliseconds.
247 if (intervalMilliseconds >= ULONG_MAX)
248 intervalMilliseconds = ULONG_MAX;
249
250 return m_condition->wait(mutex.impl(), static_cast<unsigned long>(intervalMilliseconds));
251 }
252
253 void ThreadCondition::signal()
254 {
255 m_condition->wakeOne();
256 }
257
258 void ThreadCondition::broadcast()
259 {
260 m_condition->wakeAll();
261 }
262
263 } // namespace WebCore