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