Blame qtools/qwaitcondition_win32.cpp

Packit 1c1d7e
/****************************************************************************
Packit 1c1d7e
**
Packit 1c1d7e
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
Packit 1c1d7e
** Contact: Nokia Corporation (qt-info@nokia.com)
Packit 1c1d7e
**
Packit 1c1d7e
** This file is part of the QtCore module of the Qt Toolkit.
Packit 1c1d7e
**
Packit 1c1d7e
** $QT_BEGIN_LICENSE:LGPL$
Packit 1c1d7e
** No Commercial Usage
Packit 1c1d7e
** This file contains pre-release code and may not be distributed.
Packit 1c1d7e
** You may use this file in accordance with the terms and conditions
Packit 1c1d7e
** contained in the either Technology Preview License Agreement or the
Packit 1c1d7e
** Beta Release License Agreement.
Packit 1c1d7e
**
Packit 1c1d7e
** GNU Lesser General Public License Usage
Packit 1c1d7e
** Alternatively, this file may be used under the terms of the GNU Lesser
Packit 1c1d7e
** General Public License version 2.1 as published by the Free Software
Packit 1c1d7e
** Foundation and appearing in the file LICENSE.LGPL included in the
Packit 1c1d7e
** packaging of this file.  Please review the following information to
Packit 1c1d7e
** ensure the GNU Lesser General Public License version 2.1 requirements
Packit 1c1d7e
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
Packit 1c1d7e
**
Packit 1c1d7e
** In addition, as a special exception, Nokia gives you certain
Packit 1c1d7e
** additional rights. These rights are described in the Nokia Qt LGPL
Packit 1c1d7e
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
Packit 1c1d7e
** package.
Packit 1c1d7e
**
Packit 1c1d7e
** GNU General Public License Usage
Packit 1c1d7e
** Alternatively, this file may be used under the terms of the GNU
Packit 1c1d7e
** General Public License version 3.0 as published by the Free Software
Packit 1c1d7e
** Foundation and appearing in the file LICENSE.GPL included in the
Packit 1c1d7e
** packaging of this file.  Please review the following information to
Packit 1c1d7e
** ensure the GNU General Public License version 3.0 requirements will be
Packit 1c1d7e
** met: http://www.gnu.org/copyleft/gpl.html.
Packit 1c1d7e
**
Packit 1c1d7e
** If you are unsure which license is appropriate for your use, please
Packit 1c1d7e
** contact the sales department at http://www.qtsoftware.com/contact.
Packit 1c1d7e
** $QT_END_LICENSE$
Packit 1c1d7e
**
Packit 1c1d7e
****************************************************************************/
Packit 1c1d7e
Packit 1c1d7e
#include <windows.h>
Packit 1c1d7e
#include "qwaitcondition.h"
Packit 1c1d7e
#include "qmutex.h"
Packit 1c1d7e
#include "qinternallist.h"
Packit 1c1d7e
Packit 1c1d7e
//***********************************************************************
Packit 1c1d7e
// QWaitConditionPrivate
Packit 1c1d7e
// **********************************************************************
Packit 1c1d7e
Packit 1c1d7e
class QWaitConditionEvent
Packit 1c1d7e
{
Packit 1c1d7e
public:
Packit 1c1d7e
    QWaitConditionEvent() : priority(0), wokenUp(false)
Packit 1c1d7e
    {
Packit 1c1d7e
        event = CreateEvent(NULL, TRUE, FALSE, NULL);
Packit 1c1d7e
    }
Packit 1c1d7e
    ~QWaitConditionEvent() { CloseHandle(event); }
Packit 1c1d7e
    int priority;
Packit 1c1d7e
    bool wokenUp;
Packit 1c1d7e
    HANDLE event;
Packit 1c1d7e
};
Packit 1c1d7e
Packit 1c1d7e
class EventQueue : public QInternalList<QWaitConditionEvent>
Packit 1c1d7e
{
Packit 1c1d7e
  public:
Packit 1c1d7e
    EventQueue() { setAutoDelete(TRUE); }
Packit 1c1d7e
   ~EventQueue() {}
Packit 1c1d7e
};
Packit 1c1d7e
Packit 1c1d7e
class QWaitConditionPrivate
Packit 1c1d7e
{
Packit 1c1d7e
public:
Packit 1c1d7e
    QMutex mtx;
Packit 1c1d7e
    EventQueue queue;
Packit 1c1d7e
    EventQueue freeQueue;
Packit 1c1d7e
Packit 1c1d7e
    QWaitConditionEvent *pre();
Packit 1c1d7e
    void wait(QWaitConditionEvent *wce);
Packit 1c1d7e
    void post(QWaitConditionEvent *wce);
Packit 1c1d7e
};
Packit 1c1d7e
Packit 1c1d7e
QWaitConditionEvent *QWaitConditionPrivate::pre()
Packit 1c1d7e
{
Packit 1c1d7e
    mtx.lock();
Packit 1c1d7e
    QWaitConditionEvent *wce =
Packit 1c1d7e
        freeQueue.isEmpty() ? new QWaitConditionEvent : freeQueue.take(0);
Packit 1c1d7e
    wce->priority = GetThreadPriority(GetCurrentThread());
Packit 1c1d7e
    wce->wokenUp = FALSE;
Packit 1c1d7e
Packit 1c1d7e
    // insert 'wce' into the queue (sorted by priority)
Packit 1c1d7e
    uint index = 0;
Packit 1c1d7e
    for (; index < queue.count(); ++index)
Packit 1c1d7e
    {
Packit 1c1d7e
        QWaitConditionEvent *current = queue.at(index);
Packit 1c1d7e
        if (current->priority < wce->priority)
Packit 1c1d7e
            break;
Packit 1c1d7e
    }
Packit 1c1d7e
    queue.insert(index, wce);
Packit 1c1d7e
    mtx.unlock();
Packit 1c1d7e
Packit 1c1d7e
    return wce;
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
void QWaitConditionPrivate::wait(QWaitConditionEvent *wce)
Packit 1c1d7e
{
Packit 1c1d7e
    WaitForSingleObject(wce->event, INFINITE);
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
void QWaitConditionPrivate::post(QWaitConditionEvent *wce)
Packit 1c1d7e
{
Packit 1c1d7e
    mtx.lock();
Packit 1c1d7e
Packit 1c1d7e
    // remove 'wce' from the queue
Packit 1c1d7e
    int idx = queue.find(wce);
Packit 1c1d7e
    ASSERT(idx!=-1);
Packit 1c1d7e
    queue.take(idx);
Packit 1c1d7e
    ResetEvent(wce->event);
Packit 1c1d7e
    freeQueue.append(wce);
Packit 1c1d7e
Packit 1c1d7e
    // wakeups delivered after the timeout should be forwarded to the next waiter
Packit 1c1d7e
    if (wce->wokenUp && !queue.isEmpty())
Packit 1c1d7e
    {
Packit 1c1d7e
        QWaitConditionEvent *other = queue.getFirst();
Packit 1c1d7e
        SetEvent(other->event);
Packit 1c1d7e
        other->wokenUp = TRUE;
Packit 1c1d7e
    }
Packit 1c1d7e
Packit 1c1d7e
    mtx.unlock();
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
//***********************************************************************
Packit 1c1d7e
// QWaitCondition implementation
Packit 1c1d7e
//***********************************************************************
Packit 1c1d7e
Packit 1c1d7e
QWaitCondition::QWaitCondition()
Packit 1c1d7e
{
Packit 1c1d7e
    d = new QWaitConditionPrivate;
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
QWaitCondition::~QWaitCondition()
Packit 1c1d7e
{
Packit 1c1d7e
    if (!d->queue.isEmpty())
Packit 1c1d7e
    {
Packit 1c1d7e
        qWarning("QWaitCondition: Destroyed while threads are still waiting");
Packit 1c1d7e
    }
Packit 1c1d7e
    delete d;
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
void QWaitCondition::wait(QMutex *mutex)
Packit 1c1d7e
{
Packit 1c1d7e
    if (!mutex) return;
Packit 1c1d7e
Packit 1c1d7e
    QWaitConditionEvent *wce = d->pre();
Packit 1c1d7e
    mutex->unlock();
Packit 1c1d7e
    d->wait(wce);
Packit 1c1d7e
    mutex->lock();
Packit 1c1d7e
    d->post(wce);
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
void QWaitCondition::wakeOne()
Packit 1c1d7e
{
Packit 1c1d7e
    // wake up the first waiting thread in the queue
Packit 1c1d7e
    QMutexLocker locker(&d->mtx);
Packit 1c1d7e
    for (uint i = 0; i < d->queue.count(); ++i)
Packit 1c1d7e
    {
Packit 1c1d7e
        QWaitConditionEvent *current = d->queue.at(i);
Packit 1c1d7e
        if (current->wokenUp) continue;
Packit 1c1d7e
        SetEvent(current->event);
Packit 1c1d7e
        current->wokenUp = TRUE;
Packit 1c1d7e
        break;
Packit 1c1d7e
    }
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
void QWaitCondition::wakeAll()
Packit 1c1d7e
{
Packit 1c1d7e
    // wake up the all threads in the queue
Packit 1c1d7e
    QMutexLocker locker(&d->mtx);
Packit 1c1d7e
    for (uint i = 0; i < d->queue.count(); ++i) 
Packit 1c1d7e
    {
Packit 1c1d7e
        QWaitConditionEvent *current = d->queue.at(i);
Packit 1c1d7e
        SetEvent(current->event);
Packit 1c1d7e
        current->wokenUp = TRUE;
Packit 1c1d7e
    }
Packit 1c1d7e
}
Packit 1c1d7e