Blame qtools/qwaitcondition_win32.cpp

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