|
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 |
|