initial import
[vuplus_webkit] / Source / JavaScriptCore / wtf / qt / 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 "DateMath.h"
33 #include "dtoa.h"
34 #include "CurrentTime.h"
35 #include "HashMap.h"
36 #include "MainThread.h"
37 #include "RandomNumberSeed.h"
38 #include <wtf/WTFThreadData.h>
39
40 #include <QCoreApplication>
41 #include <QMutex>
42 #include <QThread>
43 #include <QWaitCondition>
44
45 namespace WTF {
46
47 class ThreadPrivate : public QThread {
48 public:
49     ThreadPrivate(ThreadFunction entryPoint, void* data);
50     void run();
51     void* getReturnValue() { return m_returnValue; }
52 private:
53     void* m_data;
54     ThreadFunction m_entryPoint;
55     void* m_returnValue;
56 };
57
58 ThreadPrivate::ThreadPrivate(ThreadFunction entryPoint, void* data) 
59     : m_data(data)
60     , m_entryPoint(entryPoint)
61     , m_returnValue(0)
62 {
63 }
64
65 void ThreadPrivate::run()
66 {
67     m_returnValue = m_entryPoint(m_data);
68 }
69
70 class ThreadMonitor : public QObject {
71     Q_OBJECT
72 public:
73     static ThreadMonitor * instance()
74     {
75         static ThreadMonitor *instance = new ThreadMonitor();
76         return instance;
77     }
78
79 public Q_SLOTS:
80     void threadFinished()
81     {
82         sender()->deleteLater();
83     }
84 };
85
86 static Mutex* atomicallyInitializedStaticMutex;
87
88 static Mutex& threadMapMutex()
89 {
90     static Mutex mutex;
91     return mutex;
92 }
93
94 static HashMap<ThreadIdentifier, QThread*>& threadMap()
95 {
96     static HashMap<ThreadIdentifier, QThread*> map;
97     return map;
98 }
99
100 static ThreadIdentifier identifierByQthreadHandle(QThread*& thread)
101 {
102     MutexLocker locker(threadMapMutex());
103
104     HashMap<ThreadIdentifier, QThread*>::iterator i = threadMap().begin();
105     for (; i != threadMap().end(); ++i) {
106         if (i->second == thread)
107             return i->first;
108     }
109
110     return 0;
111 }
112
113 static ThreadIdentifier establishIdentifierForThread(QThread*& thread)
114 {
115     ASSERT(!identifierByQthreadHandle(thread));
116
117     MutexLocker locker(threadMapMutex());
118
119     static ThreadIdentifier identifierCount = 1;
120
121     threadMap().add(identifierCount, thread);
122
123     return identifierCount++;
124 }
125
126 static void clearThreadForIdentifier(ThreadIdentifier id)
127 {
128     MutexLocker locker(threadMapMutex());
129
130     ASSERT(threadMap().contains(id));
131
132     threadMap().remove(id);
133 }
134
135 static QThread* threadForIdentifier(ThreadIdentifier id)
136 {
137     MutexLocker locker(threadMapMutex());
138
139     return threadMap().get(id);
140 }
141
142 void initializeThreading()
143 {
144     if (!atomicallyInitializedStaticMutex) {
145         // StringImpl::empty() does not construct its static string in a threadsafe fashion,
146         // so ensure it has been initialized from here.
147         StringImpl::empty();
148         atomicallyInitializedStaticMutex = new Mutex;
149         threadMapMutex();
150         initializeRandomNumberGenerator();
151         wtfThreadData();
152 #if ENABLE(WTF_MULTIPLE_THREADS)
153         s_dtoaP5Mutex = new Mutex;
154         initializeDates();
155 #endif
156
157     }
158 }
159
160 void lockAtomicallyInitializedStaticMutex()
161 {
162     ASSERT(atomicallyInitializedStaticMutex);
163     atomicallyInitializedStaticMutex->lock();
164 }
165
166 void unlockAtomicallyInitializedStaticMutex()
167 {
168     atomicallyInitializedStaticMutex->unlock();
169 }
170
171 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
172 {
173     ThreadPrivate* thread = new ThreadPrivate(entryPoint, data);
174     if (!thread) {
175         LOG_ERROR("Failed to create thread at entry point %p with data %p", entryPoint, data);
176         return 0;
177     }
178
179     QObject::connect(thread, SIGNAL(finished()), ThreadMonitor::instance(), SLOT(threadFinished()));
180
181     thread->start();
182
183     QThread* threadRef = static_cast<QThread*>(thread);
184
185     return establishIdentifierForThread(threadRef);
186 }
187
188 void initializeCurrentThreadInternal(const char*)
189 {
190 }
191
192 int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
193 {
194     ASSERT(threadID);
195
196     QThread* thread = threadForIdentifier(threadID);
197
198     bool res = thread->wait();
199
200     clearThreadForIdentifier(threadID);
201     if (result)
202         *result = static_cast<ThreadPrivate*>(thread)->getReturnValue();
203
204     return !res;
205 }
206
207 void detachThread(ThreadIdentifier threadID)
208 {
209     ASSERT(threadID);
210     clearThreadForIdentifier(threadID);
211 }
212
213 ThreadIdentifier currentThread()
214 {
215     QThread* currentThread = QThread::currentThread();
216     if (ThreadIdentifier id = identifierByQthreadHandle(currentThread))
217         return id;
218     return establishIdentifierForThread(currentThread);
219 }
220
221 void yield()
222 {
223     QThread::yieldCurrentThread();
224 }
225
226 Mutex::Mutex()
227     : m_mutex(new QMutex())
228 {
229 }
230
231 Mutex::~Mutex()
232 {
233     delete m_mutex;
234 }
235
236 void Mutex::lock()
237 {
238     m_mutex->lock();
239 }
240
241 bool Mutex::tryLock()
242 {
243     return m_mutex->tryLock();
244 }
245
246 void Mutex::unlock()
247 {
248     m_mutex->unlock();
249 }
250
251 ThreadCondition::ThreadCondition()
252     : m_condition(new QWaitCondition())
253 {
254 }
255
256 ThreadCondition::~ThreadCondition()
257 {
258     delete m_condition;
259 }
260
261 void ThreadCondition::wait(Mutex& mutex)
262 {
263     m_condition->wait(mutex.impl());
264 }
265
266 bool ThreadCondition::timedWait(Mutex& mutex, double absoluteTime)
267 {
268     double currentTime = WTF::currentTime();
269
270     // Time is in the past - return immediately.
271     if (absoluteTime < currentTime)
272         return false;
273
274     // Time is too far in the future (and would overflow unsigned long) - wait forever.
275     if (absoluteTime - currentTime > static_cast<double>(INT_MAX) / 1000.0) {
276         wait(mutex);
277         return true;
278     }
279
280     double intervalMilliseconds = (absoluteTime - currentTime) * 1000.0;
281     return m_condition->wait(mutex.impl(), static_cast<unsigned long>(intervalMilliseconds));
282 }
283
284 void ThreadCondition::signal()
285 {
286     m_condition->wakeOne();
287 }
288
289 void ThreadCondition::broadcast()
290 {
291     m_condition->wakeAll();
292 }
293
294 } // namespace WebCore
295
296 #include "ThreadingQt.moc"