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