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