2 * Copyright (C) 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
30 #include "Threading.h"
32 #if !ENABLE(SINGLE_THREADED)
34 #include "CurrentTime.h"
36 #include "MainThread.h"
37 #include "RandomNumberSeed.h"
39 #include <QCoreApplication>
42 #include <QWaitCondition>
46 class ThreadPrivate
: public QThread
{
48 ThreadPrivate(ThreadFunction entryPoint
, void* data
);
50 void* getReturnValue() { return m_returnValue
; }
53 ThreadFunction m_entryPoint
;
57 ThreadPrivate::ThreadPrivate(ThreadFunction entryPoint
, void* data
)
59 , m_entryPoint(entryPoint
)
64 void ThreadPrivate::run()
66 m_returnValue
= m_entryPoint(m_data
);
69 class ThreadMonitor
: public QObject
{
72 static ThreadMonitor
* instance()
74 static ThreadMonitor
*instance
= new ThreadMonitor();
81 sender()->deleteLater();
85 static Mutex
* atomicallyInitializedStaticMutex
;
87 static ThreadIdentifier mainThreadIdentifier
;
89 static Mutex
& threadMapMutex()
95 static HashMap
<ThreadIdentifier
, QThread
*>& threadMap()
97 static HashMap
<ThreadIdentifier
, QThread
*> map
;
101 static ThreadIdentifier
identifierByQthreadHandle(QThread
*& thread
)
103 MutexLocker
locker(threadMapMutex());
105 HashMap
<ThreadIdentifier
, QThread
*>::iterator i
= threadMap().begin();
106 for (; i
!= threadMap().end(); ++i
) {
107 if (i
->second
== thread
)
114 static ThreadIdentifier
establishIdentifierForThread(QThread
*& thread
)
116 ASSERT(!identifierByQthreadHandle(thread
));
118 MutexLocker
locker(threadMapMutex());
120 static ThreadIdentifier identifierCount
= 1;
122 threadMap().add(identifierCount
, thread
);
124 return identifierCount
++;
127 static void clearThreadForIdentifier(ThreadIdentifier id
)
129 MutexLocker
locker(threadMapMutex());
131 ASSERT(threadMap().contains(id
));
133 threadMap().remove(id
);
136 static QThread
* threadForIdentifier(ThreadIdentifier id
)
138 MutexLocker
locker(threadMapMutex());
140 return threadMap().get(id
);
143 void initializeThreading()
145 if (!atomicallyInitializedStaticMutex
) {
146 atomicallyInitializedStaticMutex
= new Mutex
;
148 initializeRandomNumberGenerator();
149 QThread
* mainThread
= QCoreApplication::instance()->thread();
150 mainThreadIdentifier
= identifierByQthreadHandle(mainThread
);
151 if (!mainThreadIdentifier
)
152 mainThreadIdentifier
= establishIdentifierForThread(mainThread
);
153 initializeMainThread();
157 void lockAtomicallyInitializedStaticMutex()
159 ASSERT(atomicallyInitializedStaticMutex
);
160 atomicallyInitializedStaticMutex
->lock();
163 void unlockAtomicallyInitializedStaticMutex()
165 atomicallyInitializedStaticMutex
->unlock();
168 ThreadIdentifier
createThreadInternal(ThreadFunction entryPoint
, void* data
, const char*)
170 ThreadPrivate
* thread
= new ThreadPrivate(entryPoint
, data
);
172 LOG_ERROR("Failed to create thread at entry point %p with data %p", entryPoint
, data
);
176 QObject::connect(thread
, SIGNAL(finished()), ThreadMonitor::instance(), SLOT(threadFinished()));
180 QThread
* threadRef
= static_cast<QThread
*>(thread
);
182 return establishIdentifierForThread(threadRef
);
185 void initializeCurrentThreadInternal(const char*)
189 int waitForThreadCompletion(ThreadIdentifier threadID
, void** result
)
193 QThread
* thread
= threadForIdentifier(threadID
);
195 bool res
= thread
->wait();
197 clearThreadForIdentifier(threadID
);
199 *result
= static_cast<ThreadPrivate
*>(thread
)->getReturnValue();
204 void detachThread(ThreadIdentifier threadID
)
207 clearThreadForIdentifier(threadID
);
210 ThreadIdentifier
currentThread()
212 QThread
* currentThread
= QThread::currentThread();
213 if (ThreadIdentifier id
= identifierByQthreadHandle(currentThread
))
215 return establishIdentifierForThread(currentThread
);
220 return QThread::currentThread() == QCoreApplication::instance()->thread();
224 : m_mutex(new QMutex())
238 bool Mutex::tryLock()
240 return m_mutex
->tryLock();
248 ThreadCondition::ThreadCondition()
249 : m_condition(new QWaitCondition())
253 ThreadCondition::~ThreadCondition()
258 void ThreadCondition::wait(Mutex
& mutex
)
260 m_condition
->wait(mutex
.impl());
263 bool ThreadCondition::timedWait(Mutex
& mutex
, double absoluteTime
)
265 double currentTime
= WTF::currentTime();
267 // Time is in the past - return immediately.
268 if (absoluteTime
< currentTime
)
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) {
277 double intervalMilliseconds
= (absoluteTime
- currentTime
) * 1000.0;
278 return m_condition
->wait(mutex
.impl(), static_cast<unsigned long>(intervalMilliseconds
));
281 void ThreadCondition::signal()
283 m_condition
->wakeOne();
286 void ThreadCondition::broadcast()
288 m_condition
->wakeAll();
291 } // namespace WebCore
293 #include "ThreadingQt.moc"