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