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