Home | History | Annotate | Download | only in qt
      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