d-pointerize QWinOverlappedIoNotifier

Preparation for removing the qt_windows.h include from
qwinoverlappedionotifier_p.h.

Change-Id: I27ab3891962327ab5db75fbfcc3cf57c50a0d1c4
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@digia.com>
Reviewed-by: Laszlo Papp <lpapp@kde.org>
This commit is contained in:
Joerg Bornemann 2014-01-08 12:06:28 +01:00 committed by The Qt Project
parent adcab02d96
commit d19eef3bbb
2 changed files with 103 additions and 71 deletions

View File

@ -43,8 +43,10 @@
#include <qdebug.h> #include <qdebug.h>
#include <qmutex.h> #include <qmutex.h>
#include <qpointer.h> #include <qpointer.h>
#include <qqueue.h>
#include <qset.h> #include <qset.h>
#include <qthread.h> #include <qthread.h>
#include <private/qobject_p.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -79,6 +81,46 @@ QT_BEGIN_NAMESPACE
\warning This class is only available on Windows. \warning This class is only available on Windows.
*/ */
struct IOResult
{
IOResult(DWORD n = 0, DWORD e = 0, OVERLAPPED *p = 0)
: numberOfBytes(n), errorCode(e), overlapped(p)
{}
DWORD numberOfBytes;
DWORD errorCode;
OVERLAPPED *overlapped;
};
class QWinIoCompletionPort;
class QWinOverlappedIoNotifierPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QWinOverlappedIoNotifier)
public:
QWinOverlappedIoNotifierPrivate()
: hHandle(INVALID_HANDLE_VALUE)
{
}
void notify(DWORD numberOfBytes, DWORD errorCode, OVERLAPPED *overlapped);
OVERLAPPED *_q_notified();
static QWinIoCompletionPort *iocp;
static HANDLE iocpInstanceLock;
static unsigned int iocpInstanceRefCount;
HANDLE hHandle;
HANDLE hSemaphore;
HANDLE hResultsMutex;
QQueue<IOResult> results;
};
QWinIoCompletionPort *QWinOverlappedIoNotifierPrivate::iocp = 0;
HANDLE QWinOverlappedIoNotifierPrivate::iocpInstanceLock = CreateMutex(NULL, FALSE, NULL);
unsigned int QWinOverlappedIoNotifierPrivate::iocpInstanceRefCount = 0;
class QWinIoCompletionPort : protected QThread class QWinIoCompletionPort : protected QThread
{ {
public: public:
@ -109,11 +151,13 @@ public:
CloseHandle(hQueueDrainedEvent); CloseHandle(hQueueDrainedEvent);
} }
void registerNotifier(QWinOverlappedIoNotifier *notifier) void registerNotifier(QWinOverlappedIoNotifierPrivate *notifier)
{ {
HANDLE hIOCP = CreateIoCompletionPort(notifier->hHandle, hPort, reinterpret_cast<ULONG_PTR>(notifier), 0); const HANDLE hHandle = notifier->hHandle;
HANDLE hIOCP = CreateIoCompletionPort(hHandle, hPort,
reinterpret_cast<ULONG_PTR>(notifier), 0);
if (!hIOCP) { if (!hIOCP) {
qErrnoWarning("Can't associate file handle %x with I/O completion port.", notifier->hHandle); qErrnoWarning("Can't associate file handle %x with I/O completion port.", hHandle);
return; return;
} }
mutex.lock(); mutex.lock();
@ -123,7 +167,7 @@ public:
QThread::start(); QThread::start();
} }
void unregisterNotifier(QWinOverlappedIoNotifier *notifier) void unregisterNotifier(QWinOverlappedIoNotifierPrivate *notifier)
{ {
mutex.lock(); mutex.lock();
notifiers.remove(notifier); notifiers.remove(notifier);
@ -176,7 +220,8 @@ protected:
continue; continue;
} }
QWinOverlappedIoNotifier *notifier = reinterpret_cast<QWinOverlappedIoNotifier *>(pulCompletionKey); QWinOverlappedIoNotifierPrivate *notifier
= reinterpret_cast<QWinOverlappedIoNotifierPrivate *>(pulCompletionKey);
mutex.lock(); mutex.lock();
if (notifiers.contains(notifier)) if (notifiers.contains(notifier))
notifier->notify(dwBytesRead, errorCode, overlapped); notifier->notify(dwBytesRead, errorCode, overlapped);
@ -188,57 +233,62 @@ private:
const ULONG_PTR finishThreadKey; const ULONG_PTR finishThreadKey;
const ULONG_PTR drainQueueKey; const ULONG_PTR drainQueueKey;
HANDLE hPort; HANDLE hPort;
QSet<QWinOverlappedIoNotifier *> notifiers; QSet<QWinOverlappedIoNotifierPrivate *> notifiers;
QMutex mutex; QMutex mutex;
QMutex drainQueueMutex; QMutex drainQueueMutex;
HANDLE hQueueDrainedEvent; HANDLE hQueueDrainedEvent;
}; };
QWinIoCompletionPort *QWinOverlappedIoNotifier::iocp = 0;
HANDLE QWinOverlappedIoNotifier::iocpInstanceLock = CreateMutex(NULL, FALSE, NULL);
unsigned int QWinOverlappedIoNotifier::iocpInstanceRefCount = 0;
QWinOverlappedIoNotifier::QWinOverlappedIoNotifier(QObject *parent) QWinOverlappedIoNotifier::QWinOverlappedIoNotifier(QObject *parent)
: QObject(parent), : QObject(*new QWinOverlappedIoNotifierPrivate, parent)
hHandle(INVALID_HANDLE_VALUE)
{ {
WaitForSingleObject(iocpInstanceLock, INFINITE); Q_D(QWinOverlappedIoNotifier);
if (!iocp) WaitForSingleObject(d->iocpInstanceLock, INFINITE);
iocp = new QWinIoCompletionPort; if (!d->iocp)
iocpInstanceRefCount++; d->iocp = new QWinIoCompletionPort;
ReleaseMutex(iocpInstanceLock); d->iocpInstanceRefCount++;
ReleaseMutex(d->iocpInstanceLock);
hSemaphore = CreateSemaphore(NULL, 0, 255, NULL); d->hSemaphore = CreateSemaphore(NULL, 0, 255, NULL);
hResultsMutex = CreateMutex(NULL, FALSE, NULL); d->hResultsMutex = CreateMutex(NULL, FALSE, NULL);
connect(this, &QWinOverlappedIoNotifier::_q_notify, connect(this, SIGNAL(_q_notify()), this, SLOT(_q_notified()), Qt::QueuedConnection);
this, &QWinOverlappedIoNotifier::_q_notified, Qt::QueuedConnection);
} }
QWinOverlappedIoNotifier::~QWinOverlappedIoNotifier() QWinOverlappedIoNotifier::~QWinOverlappedIoNotifier()
{ {
Q_D(QWinOverlappedIoNotifier);
setEnabled(false); setEnabled(false);
CloseHandle(hResultsMutex); CloseHandle(d->hResultsMutex);
CloseHandle(hSemaphore); CloseHandle(d->hSemaphore);
WaitForSingleObject(iocpInstanceLock, INFINITE); WaitForSingleObject(d->iocpInstanceLock, INFINITE);
if (!--iocpInstanceRefCount) { if (!--d->iocpInstanceRefCount) {
delete iocp; delete d->iocp;
iocp = 0; d->iocp = 0;
} }
ReleaseMutex(iocpInstanceLock); ReleaseMutex(d->iocpInstanceLock);
} }
void QWinOverlappedIoNotifier::setHandle(HANDLE h) void QWinOverlappedIoNotifier::setHandle(HANDLE h)
{ {
hHandle = h; Q_D(QWinOverlappedIoNotifier);
d->hHandle = h;
}
HANDLE QWinOverlappedIoNotifier::handle() const
{
Q_D(const QWinOverlappedIoNotifier);
return d->hHandle;
} }
void QWinOverlappedIoNotifier::setEnabled(bool enabled) void QWinOverlappedIoNotifier::setEnabled(bool enabled)
{ {
Q_D(QWinOverlappedIoNotifier);
if (enabled) if (enabled)
iocp->registerNotifier(this); d->iocp->registerNotifier(d);
else else
iocp->unregisterNotifier(this); d->iocp->unregisterNotifier(d);
} }
/*! /*!
@ -249,18 +299,19 @@ void QWinOverlappedIoNotifier::setEnabled(bool enabled)
*/ */
bool QWinOverlappedIoNotifier::waitForNotified(int msecs, OVERLAPPED *overlapped) bool QWinOverlappedIoNotifier::waitForNotified(int msecs, OVERLAPPED *overlapped)
{ {
if (!iocp->isRunning()) { Q_D(QWinOverlappedIoNotifier);
if (!d->iocp->isRunning()) {
qWarning("Called QWinOverlappedIoNotifier::waitForNotified on inactive notifier."); qWarning("Called QWinOverlappedIoNotifier::waitForNotified on inactive notifier.");
return false; return false;
} }
forever { forever {
if (msecs == 0) if (msecs == 0)
iocp->drainQueue(); d->iocp->drainQueue();
DWORD result = WaitForSingleObject(hSemaphore, msecs == -1 ? INFINITE : DWORD(msecs)); DWORD result = WaitForSingleObject(d->hSemaphore, msecs == -1 ? INFINITE : DWORD(msecs));
if (result == WAIT_OBJECT_0) { if (result == WAIT_OBJECT_0) {
ReleaseSemaphore(hSemaphore, 1, NULL); ReleaseSemaphore(d->hSemaphore, 1, NULL);
if (_q_notified() == overlapped) if (d->_q_notified() == overlapped)
return true; return true;
continue; continue;
} else if (result == WAIT_TIMEOUT) { } else if (result == WAIT_TIMEOUT) {
@ -275,25 +326,30 @@ bool QWinOverlappedIoNotifier::waitForNotified(int msecs, OVERLAPPED *overlapped
/*! /*!
* Note: This function runs in the I/O completion port thread. * Note: This function runs in the I/O completion port thread.
*/ */
void QWinOverlappedIoNotifier::notify(DWORD numberOfBytes, DWORD errorCode, OVERLAPPED *overlapped) void QWinOverlappedIoNotifierPrivate::notify(DWORD numberOfBytes, DWORD errorCode,
OVERLAPPED *overlapped)
{ {
Q_Q(QWinOverlappedIoNotifier);
WaitForSingleObject(hResultsMutex, INFINITE); WaitForSingleObject(hResultsMutex, INFINITE);
results.enqueue(IOResult(numberOfBytes, errorCode, overlapped)); results.enqueue(IOResult(numberOfBytes, errorCode, overlapped));
ReleaseMutex(hResultsMutex); ReleaseMutex(hResultsMutex);
ReleaseSemaphore(hSemaphore, 1, NULL); ReleaseSemaphore(hSemaphore, 1, NULL);
emit _q_notify(); emit q->_q_notify();
} }
OVERLAPPED *QWinOverlappedIoNotifier::_q_notified() OVERLAPPED *QWinOverlappedIoNotifierPrivate::_q_notified()
{ {
Q_Q(QWinOverlappedIoNotifier);
if (WaitForSingleObject(hSemaphore, 0) == WAIT_OBJECT_0) { if (WaitForSingleObject(hSemaphore, 0) == WAIT_OBJECT_0) {
WaitForSingleObject(hResultsMutex, INFINITE); WaitForSingleObject(hResultsMutex, INFINITE);
IOResult ioresult = results.dequeue(); IOResult ioresult = results.dequeue();
ReleaseMutex(hResultsMutex); ReleaseMutex(hResultsMutex);
emit notified(ioresult.numberOfBytes, ioresult.errorCode, ioresult.overlapped); emit q->notified(ioresult.numberOfBytes, ioresult.errorCode, ioresult.overlapped);
return ioresult.overlapped; return ioresult.overlapped;
} }
return 0; return 0;
} }
QT_END_NAMESPACE QT_END_NAMESPACE
#include "moc_qwinoverlappedionotifier_p.cpp"

View File

@ -55,57 +55,33 @@
#include <qobject.h> #include <qobject.h>
#include <qt_windows.h> #include <qt_windows.h>
#include <qqueue.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QWinIoCompletionPort; class QWinOverlappedIoNotifierPrivate;
class Q_CORE_EXPORT QWinOverlappedIoNotifier : public QObject class Q_CORE_EXPORT QWinOverlappedIoNotifier : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(QWinOverlappedIoNotifier)
Q_DECLARE_PRIVATE(QWinOverlappedIoNotifier)
Q_PRIVATE_SLOT(d_func(), OVERLAPPED *_q_notified())
friend class QWinIoCompletionPort;
public: public:
QWinOverlappedIoNotifier(QObject *parent = 0); QWinOverlappedIoNotifier(QObject *parent = 0);
~QWinOverlappedIoNotifier(); ~QWinOverlappedIoNotifier();
void setHandle(HANDLE h); void setHandle(HANDLE h);
HANDLE handle() const { return hHandle; } HANDLE handle() const;
void setEnabled(bool enabled); void setEnabled(bool enabled);
bool waitForNotified(int msecs, OVERLAPPED *overlapped); bool waitForNotified(int msecs, OVERLAPPED *overlapped);
Q_SIGNALS: Q_SIGNALS:
void notified(DWORD numberOfBytes, DWORD errorCode, OVERLAPPED *overlapped); void notified(DWORD numberOfBytes, DWORD errorCode, OVERLAPPED *overlapped);
#if !defined(Q_QDOC)
void _q_notify(); void _q_notify();
#endif
private Q_SLOTS:
OVERLAPPED *_q_notified();
private:
void notify(DWORD numberOfBytes, DWORD errorCode, OVERLAPPED *overlapped);
private:
static QWinIoCompletionPort *iocp;
static HANDLE iocpInstanceLock;
static unsigned int iocpInstanceRefCount;
HANDLE hHandle;
HANDLE hSemaphore;
HANDLE hResultsMutex;
struct IOResult
{
IOResult(DWORD n = 0, DWORD e = 0, OVERLAPPED *p = 0)
: numberOfBytes(n), errorCode(e), overlapped(p)
{}
DWORD numberOfBytes;
DWORD errorCode;
OVERLAPPED *overlapped;
};
QQueue<IOResult> results;
friend class QWinIoCompletionPort;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE