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 #include "CurrentTime.h"
34 #include "MainThread.h"
35 #include "RandomNumberSeed.h"
37 #include <QCoreApplication>
40 #include <QWaitCondition>
44 class ThreadPrivate
: public QThread
{
46 ThreadPrivate(ThreadFunction entryPoint
, void* data
);
48 void* getReturnValue() { return m_returnValue
; }
51 ThreadFunction m_entryPoint
;
55 ThreadPrivate::ThreadPrivate(ThreadFunction entryPoint
, void* data
)
57 , m_entryPoint(entryPoint
)
62 void ThreadPrivate::run()
64 m_returnValue
= m_entryPoint(m_data
);
68 static Mutex
* atomicallyInitializedStaticMutex
;
70 static ThreadIdentifier mainThreadIdentifier
;
72 static Mutex
& threadMapMutex()
78 static HashMap
<ThreadIdentifier
, QThread
*>& threadMap()
80 static HashMap
<ThreadIdentifier
, QThread
*> map
;
84 static ThreadIdentifier
identifierByQthreadHandle(QThread
*& thread
)
86 MutexLocker
locker(threadMapMutex());
88 HashMap
<ThreadIdentifier
, QThread
*>::iterator i
= threadMap().begin();
89 for (; i
!= threadMap().end(); ++i
) {
90 if (i
->second
== thread
)
97 static ThreadIdentifier
establishIdentifierForThread(QThread
*& thread
)
99 ASSERT(!identifierByQthreadHandle(thread
));
101 MutexLocker
locker(threadMapMutex());
103 static ThreadIdentifier identifierCount
= 1;
105 threadMap().add(identifierCount
, thread
);
107 return identifierCount
++;
110 static void clearThreadForIdentifier(ThreadIdentifier id
)
112 MutexLocker
locker(threadMapMutex());
114 ASSERT(threadMap().contains(id
));
116 threadMap().remove(id
);
119 static QThread
* threadForIdentifier(ThreadIdentifier id
)
121 MutexLocker
locker(threadMapMutex());
123 return threadMap().get(id
);
126 void initializeThreading()
128 if (!atomicallyInitializedStaticMutex
) {
129 atomicallyInitializedStaticMutex
= new Mutex
;
131 initializeRandomNumberGenerator();
132 QThread
* mainThread
= QCoreApplication::instance()->thread();
133 mainThreadIdentifier
= identifierByQthreadHandle(mainThread
);
134 if (!mainThreadIdentifier
)
135 mainThreadIdentifier
= establishIdentifierForThread(mainThread
);
136 initializeMainThread();
140 void lockAtomicallyInitializedStaticMutex()
142 ASSERT(atomicallyInitializedStaticMutex
);
143 atomicallyInitializedStaticMutex
->lock();
146 void unlockAtomicallyInitializedStaticMutex()
148 atomicallyInitializedStaticMutex
->unlock();
151 ThreadIdentifier
createThreadInternal(ThreadFunction entryPoint
, void* data
, const char*)
153 ThreadPrivate
* thread
= new ThreadPrivate(entryPoint
, data
);
155 LOG_ERROR("Failed to create thread at entry point %p with data %p", entryPoint
, data
);
160 QThread
* threadRef
= static_cast<QThread
*>(thread
);
162 return establishIdentifierForThread(threadRef
);
165 int waitForThreadCompletion(ThreadIdentifier threadID
, void** result
)
169 QThread
* thread
= threadForIdentifier(threadID
);
171 bool res
= thread
->wait();
173 clearThreadForIdentifier(threadID
);
175 *result
= static_cast<ThreadPrivate
*>(thread
)->getReturnValue();
180 void detachThread(ThreadIdentifier
)
184 ThreadIdentifier
currentThread()
186 QThread
* currentThread
= QThread::currentThread();
187 if (ThreadIdentifier id
= identifierByQthreadHandle(currentThread
))
189 return establishIdentifierForThread(currentThread
);
194 return currentThread() == mainThreadIdentifier
;
198 : m_mutex(new QMutex())
212 bool Mutex::tryLock()
214 return m_mutex
->tryLock();
222 ThreadCondition::ThreadCondition()
223 : m_condition(new QWaitCondition())
227 ThreadCondition::~ThreadCondition()
232 void ThreadCondition::wait(Mutex
& mutex
)
234 m_condition
->wait(mutex
.impl());
237 bool ThreadCondition::timedWait(Mutex
& mutex
, double absoluteTime
)
239 double currentTime
= WTF::currentTime();
241 // Time is in the past - return immediately.
242 if (absoluteTime
< currentTime
)
245 double intervalMilliseconds
= (absoluteTime
- currentTime
) * 1000.0;
246 // Qt defines wait for up to ULONG_MAX milliseconds.
247 if (intervalMilliseconds
>= ULONG_MAX
)
248 intervalMilliseconds
= ULONG_MAX
;
250 return m_condition
->wait(mutex
.impl(), static_cast<unsigned long>(intervalMilliseconds
));
253 void ThreadCondition::signal()
255 m_condition
->wakeOne();
258 void ThreadCondition::broadcast()
260 m_condition
->wakeAll();
263 } // namespace WebCore