<rdar://problem/6467376> Race condition in WTF::currentThread can lead to a thread...
[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 identifierByQthreadHandle(QThread*& thread)
84 {
85     MutexLocker locker(threadMapMutex());
86
87     HashMap<ThreadIdentifier, QThread*>::iterator i = threadMap().begin();
88     for (; i != threadMap().end(); ++i) {
89         if (i->second == thread)
90             return i->first;
91     }
92
93     return 0;
94 }
95
96 static ThreadIdentifier establishIdentifierForThread(QThread*& thread)
97 {
98     ASSERT(!identifierByQthreadHandle(thread));
99
100     MutexLocker locker(threadMapMutex());
101
102     static ThreadIdentifier identifierCount = 1;
103
104     threadMap().add(identifierCount, thread);
105
106     return identifierCount++;
107 }
108
109 static void clearThreadForIdentifier(ThreadIdentifier id)
110 {
111     MutexLocker locker(threadMapMutex());
112
113     ASSERT(threadMap().contains(id));
114
115     threadMap().remove(id);
116 }
117
118 static QThread* threadForIdentifier(ThreadIdentifier id)
119 {
120     MutexLocker locker(threadMapMutex());
121
122     return threadMap().get(id);
123 }
124
125 void initializeThreading()
126 {
127     if (!atomicallyInitializedStaticMutex) {
128         atomicallyInitializedStaticMutex = new Mutex;
129         threadMapMutex();
130         initializeRandomNumberGenerator();
131         QThread* mainThread = QCoreApplication::instance()->thread();
132         mainThreadIdentifier = identifierByQthreadHandle(mainThread);
133         if (!mainThreadIdentifier)
134             mainThreadIdentifier = establishIdentifierForThread(mainThread);
135         initializeMainThread();
136     }
137 }
138
139 void lockAtomicallyInitializedStaticMutex()
140 {
141     ASSERT(atomicallyInitializedStaticMutex);
142     atomicallyInitializedStaticMutex->lock();
143 }
144
145 void unlockAtomicallyInitializedStaticMutex()
146 {
147     atomicallyInitializedStaticMutex->unlock();
148 }
149
150 ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char*)
151 {
152     ThreadPrivate* thread = new ThreadPrivate(entryPoint, data);
153     if (!thread) {
154         LOG_ERROR("Failed to create thread at entry point %p with data %p", entryPoint, data);
155         return 0;
156     }
157     thread->start();
158
159     QThread* threadRef = static_cast<QThread*>(thread);
160
161     return establishIdentifierForThread(threadRef);
162 }
163
164 int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
165 {
166     ASSERT(threadID);
167
168     QThread* thread = threadForIdentifier(threadID);
169
170     bool res = thread->wait();
171
172     clearThreadForIdentifier(threadID);
173     if (result)
174         *result = static_cast<ThreadPrivate*>(thread)->getReturnValue();
175
176     return !res;
177 }
178
179 void detachThread(ThreadIdentifier)
180 {
181 }
182
183 ThreadIdentifier currentThread()
184 {
185     QThread* currentThread = QThread::currentThread();
186     if (ThreadIdentifier id = identifierByQthreadHandle(currentThread))
187         return id;
188     return establishIdentifierForThread(currentThread);
189 }
190
191 bool isMainThread()
192 {
193     return currentThread() == mainThreadIdentifier;
194 }
195
196 Mutex::Mutex()
197     : m_mutex(new QMutex())
198 {
199 }
200
201 Mutex::~Mutex()
202 {
203     delete m_mutex;
204 }
205
206 void Mutex::lock()
207 {
208     m_mutex->lock();
209 }
210
211 bool Mutex::tryLock()
212 {
213     return m_mutex->tryLock();
214 }
215
216 void Mutex::unlock()
217 {
218     m_mutex->unlock();
219 }
220
221 ThreadCondition::ThreadCondition()
222     : m_condition(new QWaitCondition())
223 {
224 }
225
226 ThreadCondition::~ThreadCondition()
227 {
228     delete m_condition;
229 }
230
231 void ThreadCondition::wait(Mutex& mutex)
232 {
233     m_condition->wait(mutex.impl());
234 }
235
236 bool ThreadCondition::timedWait(Mutex& mutex, double secondsToWait)
237 {
238     if (secondsToWait < 0.0) {
239         wait(mutex);
240         return true;
241     }
242
243     unsigned long millisecondsToWait = static_cast<unsigned long>(secondsToWait * 1000.0);
244     return m_condition->wait(mutex.impl(), millisecondsToWait);
245 }
246
247 void ThreadCondition::signal()
248 {
249     m_condition->wakeOne();
250 }
251
252 void ThreadCondition::broadcast()
253 {
254     m_condition->wakeAll();
255 }
256
257 } // namespace WebCore