1 /* 2 * Copyright (C) 2007 Apple Inc. All rights reserved. 3 * Copyright (C) 2007 Justin Haygood (jhaygood (at) 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(); 50 void* getReturnValue() { return m_returnValue; } 51 private: 52 void* m_data; 53 ThreadFunction m_entryPoint; 54 void* m_returnValue; 55 }; 56 57 ThreadPrivate::ThreadPrivate(ThreadFunction entryPoint, void* data) 58 : m_data(data) 59 , m_entryPoint(entryPoint) 60 , m_returnValue(0) 61 { 62 } 63 64 void ThreadPrivate::run() 65 { 66 m_returnValue = m_entryPoint(m_data); 67 } 68 69 class ThreadMonitor : public QObject { 70 Q_OBJECT 71 public: 72 static ThreadMonitor * instance() 73 { 74 static ThreadMonitor *instance = new ThreadMonitor(); 75 return instance; 76 } 77 78 public Q_SLOTS: 79 void threadFinished() 80 { 81 sender()->deleteLater(); 82 } 83 }; 84 85 static Mutex* atomicallyInitializedStaticMutex; 86 87 static Mutex& threadMapMutex() 88 { 89 static Mutex mutex; 90 return mutex; 91 } 92 93 static HashMap<ThreadIdentifier, QThread*>& threadMap() 94 { 95 static HashMap<ThreadIdentifier, QThread*> map; 96 return map; 97 } 98 99 static 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 112 static 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 125 static void clearThreadForIdentifier(ThreadIdentifier id) 126 { 127 MutexLocker locker(threadMapMutex()); 128 129 ASSERT(threadMap().contains(id)); 130 131 threadMap().remove(id); 132 } 133 134 static QThread* threadForIdentifier(ThreadIdentifier id) 135 { 136 MutexLocker locker(threadMapMutex()); 137 138 return threadMap().get(id); 139 } 140 141 void initializeThreading() 142 { 143 if (!atomicallyInitializedStaticMutex) { 144 atomicallyInitializedStaticMutex = new Mutex; 145 threadMapMutex(); 146 initializeRandomNumberGenerator(); 147 } 148 } 149 150 void lockAtomicallyInitializedStaticMutex() 151 { 152 ASSERT(atomicallyInitializedStaticMutex); 153 atomicallyInitializedStaticMutex->lock(); 154 } 155 156 void unlockAtomicallyInitializedStaticMutex() 157 { 158 atomicallyInitializedStaticMutex->unlock(); 159 } 160 161 ThreadIdentifier 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 178 void initializeCurrentThreadInternal(const char*) 179 { 180 } 181 182 int 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 197 void detachThread(ThreadIdentifier threadID) 198 { 199 ASSERT(threadID); 200 clearThreadForIdentifier(threadID); 201 } 202 203 ThreadIdentifier currentThread() 204 { 205 QThread* currentThread = QThread::currentThread(); 206 if (ThreadIdentifier id = identifierByQthreadHandle(currentThread)) 207 return id; 208 return establishIdentifierForThread(currentThread); 209 } 210 211 void yield() 212 { 213 QThread::yieldCurrentThread(); 214 } 215 216 Mutex::Mutex() 217 : m_mutex(new QMutex()) 218 { 219 } 220 221 Mutex::~Mutex() 222 { 223 delete m_mutex; 224 } 225 226 void Mutex::lock() 227 { 228 m_mutex->lock(); 229 } 230 231 bool Mutex::tryLock() 232 { 233 return m_mutex->tryLock(); 234 } 235 236 void Mutex::unlock() 237 { 238 m_mutex->unlock(); 239 } 240 241 ThreadCondition::ThreadCondition() 242 : m_condition(new QWaitCondition()) 243 { 244 } 245 246 ThreadCondition::~ThreadCondition() 247 { 248 delete m_condition; 249 } 250 251 void ThreadCondition::wait(Mutex& mutex) 252 { 253 m_condition->wait(mutex.impl()); 254 } 255 256 bool 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 274 void ThreadCondition::signal() 275 { 276 m_condition->wakeOne(); 277 } 278 279 void ThreadCondition::broadcast() 280 { 281 m_condition->wakeAll(); 282 } 283 284 } // namespace WebCore 285 286 #include "ThreadingQt.moc" 287 288 #endif 289