Remove QWinOverlappedIoNotifier
This class in unused in qtbase since Qt 5.6.1. The only outside usage was in qtserialport, which got its own copy of QWinOverlappedIoNotifier in commit qtserialport/65dba188. Change-Id: I7668e67a1cc49c4418c66141784b180cd5f9d479 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@qt.io>
This commit is contained in:
parent
1e503d7634
commit
ea57a23d7a
@ -118,16 +118,14 @@ win32 {
|
||||
!winrt {
|
||||
HEADERS += \
|
||||
io/qwindowspipereader_p.h \
|
||||
io/qwindowspipewriter_p.h \
|
||||
io/qwinoverlappedionotifier_p.h
|
||||
io/qwindowspipewriter_p.h
|
||||
|
||||
SOURCES += \
|
||||
io/qsettings_win.cpp \
|
||||
io/qstandardpaths_win.cpp \
|
||||
io/qstorageinfo_win.cpp \
|
||||
io/qwindowspipereader.cpp \
|
||||
io/qwindowspipewriter.cpp \
|
||||
io/qwinoverlappedionotifier.cpp
|
||||
io/qwindowspipewriter.cpp
|
||||
|
||||
LIBS += -lmpr
|
||||
} else {
|
||||
|
@ -1,428 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtCore module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qwinoverlappedionotifier_p.h"
|
||||
#include <qdebug.h>
|
||||
#include <qatomic.h>
|
||||
#include <qelapsedtimer.h>
|
||||
#include <qmutex.h>
|
||||
#include <qpointer.h>
|
||||
#include <qqueue.h>
|
||||
#include <qset.h>
|
||||
#include <qthread.h>
|
||||
#include <qt_windows.h>
|
||||
#include <private/qobject_p.h>
|
||||
#include <private/qiodevice_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
/*!
|
||||
\class QWinOverlappedIoNotifier
|
||||
\inmodule QtCore
|
||||
\brief The QWinOverlappedIoNotifier class provides support for overlapped I/O notifications on Windows.
|
||||
\since 5.0
|
||||
\internal
|
||||
|
||||
The QWinOverlappedIoNotifier class makes it possible to use efficient
|
||||
overlapped (asynchronous) I/O notifications on Windows by using an
|
||||
I/O completion port.
|
||||
|
||||
Once you have obtained a file handle, you can use setHandle() to get
|
||||
notifications for I/O operations. Whenever an I/O operation completes,
|
||||
the notified() signal is emitted which will pass the number of transferred
|
||||
bytes, the operation's error code and a pointer to the operation's
|
||||
OVERLAPPED object to the receiver.
|
||||
|
||||
Every handle that supports overlapped I/O can be used by
|
||||
QWinOverlappedIoNotifier. That includes file handles, TCP sockets
|
||||
and named pipes.
|
||||
|
||||
Note that you must not use ReadFileEx() and WriteFileEx() together
|
||||
with QWinOverlappedIoNotifier. They are not supported as they use a
|
||||
different I/O notification mechanism.
|
||||
|
||||
The hEvent member in the OVERLAPPED structure passed to ReadFile()
|
||||
or WriteFile() is ignored and can be used for other purposes.
|
||||
|
||||
\warning This class is only available on Windows.
|
||||
|
||||
Due to peculiarities of the Windows I/O completion port API, users of
|
||||
QWinOverlappedIoNotifier must pay attention to the following restrictions:
|
||||
\list
|
||||
\li File handles with a QWinOverlappedIoNotifer are assigned to an I/O
|
||||
completion port until the handle is closed. It is impossible to
|
||||
disassociate the file handle from the I/O completion port.
|
||||
\li There can be only one QWinOverlappedIoNotifer per file handle. Creating
|
||||
another QWinOverlappedIoNotifier for that file, even with a duplicated
|
||||
handle, will fail.
|
||||
\li Certain Windows API functions are unavailable for file handles that are
|
||||
assigned to an I/O completion port. This includes the functions
|
||||
\c{ReadFileEx} and \c{WriteFileEx}.
|
||||
\endlist
|
||||
See also the remarks in the MSDN documentation for the
|
||||
\c{CreateIoCompletionPort} function.
|
||||
*/
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
OVERLAPPED *waitForAnyNotified(int msecs);
|
||||
void notify(DWORD numberOfBytes, DWORD errorCode, OVERLAPPED *overlapped);
|
||||
void _q_notified();
|
||||
OVERLAPPED *dispatchNextIoResult();
|
||||
|
||||
static QWinIoCompletionPort *iocp;
|
||||
static HANDLE iocpInstanceLock;
|
||||
static unsigned int iocpInstanceRefCount;
|
||||
HANDLE hHandle;
|
||||
HANDLE hSemaphore;
|
||||
HANDLE hResultsMutex;
|
||||
QAtomicInt waiting;
|
||||
QQueue<IOResult> results;
|
||||
};
|
||||
|
||||
QWinIoCompletionPort *QWinOverlappedIoNotifierPrivate::iocp = 0;
|
||||
HANDLE QWinOverlappedIoNotifierPrivate::iocpInstanceLock = CreateMutex(NULL, FALSE, NULL);
|
||||
unsigned int QWinOverlappedIoNotifierPrivate::iocpInstanceRefCount = 0;
|
||||
|
||||
|
||||
class QWinIoCompletionPort : protected QThread
|
||||
{
|
||||
public:
|
||||
QWinIoCompletionPort()
|
||||
: finishThreadKey(reinterpret_cast<ULONG_PTR>(this)),
|
||||
drainQueueKey(reinterpret_cast<ULONG_PTR>(this + 1)),
|
||||
hPort(INVALID_HANDLE_VALUE)
|
||||
{
|
||||
setObjectName(QLatin1String("I/O completion port thread"));
|
||||
HANDLE hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
|
||||
if (!hIOCP) {
|
||||
qErrnoWarning("CreateIoCompletionPort failed.");
|
||||
return;
|
||||
}
|
||||
hPort = hIOCP;
|
||||
hQueueDrainedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
if (!hQueueDrainedEvent) {
|
||||
qErrnoWarning("CreateEvent failed.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
~QWinIoCompletionPort()
|
||||
{
|
||||
PostQueuedCompletionStatus(hPort, 0, finishThreadKey, NULL);
|
||||
QThread::wait();
|
||||
CloseHandle(hPort);
|
||||
CloseHandle(hQueueDrainedEvent);
|
||||
}
|
||||
|
||||
void registerNotifier(QWinOverlappedIoNotifierPrivate *notifier)
|
||||
{
|
||||
const HANDLE hHandle = notifier->hHandle;
|
||||
HANDLE hIOCP = CreateIoCompletionPort(hHandle, hPort,
|
||||
reinterpret_cast<ULONG_PTR>(notifier), 0);
|
||||
if (!hIOCP) {
|
||||
qErrnoWarning("Can't associate file handle %x with I/O completion port.", hHandle);
|
||||
return;
|
||||
}
|
||||
mutex.lock();
|
||||
notifiers += notifier;
|
||||
mutex.unlock();
|
||||
if (!QThread::isRunning())
|
||||
QThread::start();
|
||||
}
|
||||
|
||||
void unregisterNotifier(QWinOverlappedIoNotifierPrivate *notifier)
|
||||
{
|
||||
mutex.lock();
|
||||
notifiers.remove(notifier);
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
void drainQueue()
|
||||
{
|
||||
QMutexLocker locker(&drainQueueMutex);
|
||||
ResetEvent(hQueueDrainedEvent);
|
||||
PostQueuedCompletionStatus(hPort, 0, drainQueueKey, NULL);
|
||||
WaitForSingleObject(hQueueDrainedEvent, INFINITE);
|
||||
}
|
||||
|
||||
using QThread::isRunning;
|
||||
|
||||
protected:
|
||||
void run()
|
||||
{
|
||||
DWORD dwBytesRead;
|
||||
ULONG_PTR pulCompletionKey;
|
||||
OVERLAPPED *overlapped;
|
||||
DWORD msecs = INFINITE;
|
||||
|
||||
forever {
|
||||
BOOL success = GetQueuedCompletionStatus(hPort,
|
||||
&dwBytesRead,
|
||||
&pulCompletionKey,
|
||||
&overlapped,
|
||||
msecs);
|
||||
|
||||
DWORD errorCode = success ? ERROR_SUCCESS : GetLastError();
|
||||
if (!success && !overlapped) {
|
||||
if (!msecs) {
|
||||
// Time out in drain mode. The completion status queue is empty.
|
||||
msecs = INFINITE;
|
||||
SetEvent(hQueueDrainedEvent);
|
||||
continue;
|
||||
}
|
||||
qErrnoWarning(errorCode, "GetQueuedCompletionStatus failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pulCompletionKey == finishThreadKey)
|
||||
return;
|
||||
if (pulCompletionKey == drainQueueKey) {
|
||||
// Enter drain mode.
|
||||
Q_ASSERT(msecs == INFINITE);
|
||||
msecs = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
QWinOverlappedIoNotifierPrivate *notifier
|
||||
= reinterpret_cast<QWinOverlappedIoNotifierPrivate *>(pulCompletionKey);
|
||||
mutex.lock();
|
||||
if (notifiers.contains(notifier))
|
||||
notifier->notify(dwBytesRead, errorCode, overlapped);
|
||||
mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const ULONG_PTR finishThreadKey;
|
||||
const ULONG_PTR drainQueueKey;
|
||||
HANDLE hPort;
|
||||
QSet<QWinOverlappedIoNotifierPrivate *> notifiers;
|
||||
QMutex mutex;
|
||||
QMutex drainQueueMutex;
|
||||
HANDLE hQueueDrainedEvent;
|
||||
};
|
||||
|
||||
|
||||
QWinOverlappedIoNotifier::QWinOverlappedIoNotifier(QObject *parent)
|
||||
: QObject(*new QWinOverlappedIoNotifierPrivate, parent)
|
||||
{
|
||||
Q_D(QWinOverlappedIoNotifier);
|
||||
WaitForSingleObject(d->iocpInstanceLock, INFINITE);
|
||||
if (!d->iocp)
|
||||
d->iocp = new QWinIoCompletionPort;
|
||||
d->iocpInstanceRefCount++;
|
||||
ReleaseMutex(d->iocpInstanceLock);
|
||||
|
||||
d->hSemaphore = CreateSemaphore(NULL, 0, 255, NULL);
|
||||
d->hResultsMutex = CreateMutex(NULL, FALSE, NULL);
|
||||
connect(this, SIGNAL(_q_notify()), this, SLOT(_q_notified()), Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
QWinOverlappedIoNotifier::~QWinOverlappedIoNotifier()
|
||||
{
|
||||
Q_D(QWinOverlappedIoNotifier);
|
||||
setEnabled(false);
|
||||
CloseHandle(d->hResultsMutex);
|
||||
CloseHandle(d->hSemaphore);
|
||||
|
||||
WaitForSingleObject(d->iocpInstanceLock, INFINITE);
|
||||
if (!--d->iocpInstanceRefCount) {
|
||||
delete d->iocp;
|
||||
d->iocp = 0;
|
||||
}
|
||||
ReleaseMutex(d->iocpInstanceLock);
|
||||
}
|
||||
|
||||
void QWinOverlappedIoNotifier::setHandle(Qt::HANDLE h)
|
||||
{
|
||||
Q_D(QWinOverlappedIoNotifier);
|
||||
d->hHandle = h;
|
||||
}
|
||||
|
||||
Qt::HANDLE QWinOverlappedIoNotifier::handle() const
|
||||
{
|
||||
Q_D(const QWinOverlappedIoNotifier);
|
||||
return d->hHandle;
|
||||
}
|
||||
|
||||
void QWinOverlappedIoNotifier::setEnabled(bool enabled)
|
||||
{
|
||||
Q_D(QWinOverlappedIoNotifier);
|
||||
if (enabled)
|
||||
d->iocp->registerNotifier(d);
|
||||
else
|
||||
d->iocp->unregisterNotifier(d);
|
||||
}
|
||||
|
||||
OVERLAPPED *QWinOverlappedIoNotifierPrivate::waitForAnyNotified(int msecs)
|
||||
{
|
||||
if (!iocp->isRunning()) {
|
||||
qWarning("Called QWinOverlappedIoNotifier::waitForAnyNotified on inactive notifier.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (msecs == 0)
|
||||
iocp->drainQueue();
|
||||
|
||||
const DWORD wfso = WaitForSingleObject(hSemaphore, msecs == -1 ? INFINITE : DWORD(msecs));
|
||||
switch (wfso) {
|
||||
case WAIT_OBJECT_0:
|
||||
return dispatchNextIoResult();
|
||||
case WAIT_TIMEOUT:
|
||||
return 0;
|
||||
default:
|
||||
qErrnoWarning("QWinOverlappedIoNotifier::waitForAnyNotified: WaitForSingleObject failed.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
class QScopedAtomicIntIncrementor
|
||||
{
|
||||
public:
|
||||
QScopedAtomicIntIncrementor(QAtomicInt &i)
|
||||
: m_int(i)
|
||||
{
|
||||
++m_int;
|
||||
}
|
||||
|
||||
~QScopedAtomicIntIncrementor()
|
||||
{
|
||||
--m_int;
|
||||
}
|
||||
|
||||
private:
|
||||
QAtomicInt &m_int;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Wait synchronously for any notified signal.
|
||||
*
|
||||
* The function returns a pointer to the OVERLAPPED object corresponding to the completed I/O
|
||||
* operation. In case no I/O operation was completed during the \a msec timeout, this function
|
||||
* returns a null pointer.
|
||||
*/
|
||||
OVERLAPPED *QWinOverlappedIoNotifier::waitForAnyNotified(int msecs)
|
||||
{
|
||||
Q_D(QWinOverlappedIoNotifier);
|
||||
QScopedAtomicIntIncrementor saii(d->waiting);
|
||||
OVERLAPPED *result = d->waitForAnyNotified(msecs);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Wait synchronously for the notified signal.
|
||||
*
|
||||
* The function returns true if the notified signal was emitted for
|
||||
* the I/O operation that corresponds to the OVERLAPPED object.
|
||||
*/
|
||||
bool QWinOverlappedIoNotifier::waitForNotified(int msecs, OVERLAPPED *overlapped)
|
||||
{
|
||||
Q_D(QWinOverlappedIoNotifier);
|
||||
QScopedAtomicIntIncrementor saii(d->waiting);
|
||||
int t = msecs;
|
||||
QElapsedTimer stopWatch;
|
||||
stopWatch.start();
|
||||
forever {
|
||||
OVERLAPPED *triggeredOverlapped = waitForAnyNotified(t);
|
||||
if (!triggeredOverlapped)
|
||||
return false;
|
||||
if (triggeredOverlapped == overlapped)
|
||||
return true;
|
||||
t = qt_subtract_from_timeout(msecs, stopWatch.elapsed());
|
||||
if (t == 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Note: This function runs in the I/O completion port thread.
|
||||
*/
|
||||
void QWinOverlappedIoNotifierPrivate::notify(DWORD numberOfBytes, DWORD errorCode,
|
||||
OVERLAPPED *overlapped)
|
||||
{
|
||||
Q_Q(QWinOverlappedIoNotifier);
|
||||
WaitForSingleObject(hResultsMutex, INFINITE);
|
||||
results.enqueue(IOResult(numberOfBytes, errorCode, overlapped));
|
||||
ReleaseMutex(hResultsMutex);
|
||||
ReleaseSemaphore(hSemaphore, 1, NULL);
|
||||
if (!waiting)
|
||||
emit q->_q_notify();
|
||||
}
|
||||
|
||||
void QWinOverlappedIoNotifierPrivate::_q_notified()
|
||||
{
|
||||
if (WaitForSingleObject(hSemaphore, 0) == WAIT_OBJECT_0)
|
||||
dispatchNextIoResult();
|
||||
}
|
||||
|
||||
OVERLAPPED *QWinOverlappedIoNotifierPrivate::dispatchNextIoResult()
|
||||
{
|
||||
Q_Q(QWinOverlappedIoNotifier);
|
||||
WaitForSingleObject(hResultsMutex, INFINITE);
|
||||
IOResult ioresult = results.dequeue();
|
||||
ReleaseMutex(hResultsMutex);
|
||||
emit q->notified(ioresult.numberOfBytes, ioresult.errorCode, ioresult.overlapped);
|
||||
return ioresult.overlapped;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#include "moc_qwinoverlappedionotifier_p.cpp"
|
@ -1,90 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtCore module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QWINOVERLAPPEDIONOTIFIER_P_H
|
||||
#define QWINOVERLAPPEDIONOTIFIER_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include <QtCore/private/qglobal_p.h>
|
||||
#include <qobject.h>
|
||||
|
||||
typedef struct _OVERLAPPED OVERLAPPED;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QWinOverlappedIoNotifierPrivate;
|
||||
|
||||
class Q_CORE_EXPORT QWinOverlappedIoNotifier : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(QWinOverlappedIoNotifier)
|
||||
Q_DECLARE_PRIVATE(QWinOverlappedIoNotifier)
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_notified())
|
||||
friend class QWinIoCompletionPort;
|
||||
public:
|
||||
QWinOverlappedIoNotifier(QObject *parent = 0);
|
||||
~QWinOverlappedIoNotifier();
|
||||
|
||||
void setHandle(Qt::HANDLE h);
|
||||
Qt::HANDLE handle() const;
|
||||
|
||||
void setEnabled(bool enabled);
|
||||
OVERLAPPED *waitForAnyNotified(int msecs);
|
||||
bool waitForNotified(int msecs, OVERLAPPED *overlapped);
|
||||
|
||||
Q_SIGNALS:
|
||||
void notified(quint32 numberOfBytes, quint32 errorCode, OVERLAPPED *overlapped);
|
||||
#if !defined(Q_QDOC)
|
||||
void _q_notify();
|
||||
#endif
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QWINOVERLAPPEDIONOTIFIER_P_H
|
@ -34,12 +34,6 @@ SUBDIRS=\
|
||||
qurl \
|
||||
qurlinternal \
|
||||
qurlquery \
|
||||
qwinoverlappedionotifier \
|
||||
|
||||
!win32 {
|
||||
SUBDIRS -=\
|
||||
qwinoverlappedionotifier
|
||||
}
|
||||
|
||||
!qtHaveModule(gui): SUBDIRS -= \
|
||||
qdatastream \
|
||||
@ -73,5 +67,4 @@ win32:!qtConfig(private_tests): SUBDIRS -= \
|
||||
qprocess-noapplication
|
||||
|
||||
winrt: SUBDIRS -= \
|
||||
qstorageinfo \
|
||||
qwinoverlappedionotifier
|
||||
qstorageinfo
|
||||
|
@ -1,4 +0,0 @@
|
||||
CONFIG += testcase
|
||||
TARGET = tst_qwinoverlappedionotifier
|
||||
QT = core-private testlib
|
||||
SOURCES = tst_qwinoverlappedionotifier.cpp
|
@ -1,331 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the test suite of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
#include <private/qwinoverlappedionotifier_p.h>
|
||||
#include <qbytearray.h>
|
||||
#include <qt_windows.h>
|
||||
|
||||
#ifndef PIPE_REJECT_REMOTE_CLIENTS
|
||||
#define PIPE_REJECT_REMOTE_CLIENTS 0x08
|
||||
#endif
|
||||
|
||||
class tst_QWinOverlappedIoNotifier : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void initTestCase();
|
||||
void readFile_data();
|
||||
void readFile();
|
||||
void waitForNotified_data();
|
||||
void waitForNotified();
|
||||
void waitForAnyNotified();
|
||||
void brokenPipe();
|
||||
void multipleOperations();
|
||||
|
||||
private:
|
||||
QFileInfo sourceFileInfo;
|
||||
DWORD notifiedBytesRead;
|
||||
DWORD notifiedErrorCode;
|
||||
};
|
||||
|
||||
class NotifierSink : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
NotifierSink(QWinOverlappedIoNotifier *notifier)
|
||||
: QObject(notifier),
|
||||
threshold(1)
|
||||
{
|
||||
connect(notifier, &QWinOverlappedIoNotifier::notified, this, &NotifierSink::notified);
|
||||
}
|
||||
|
||||
protected slots:
|
||||
void notified(DWORD bytesRead, DWORD errorCode, OVERLAPPED *overlapped)
|
||||
{
|
||||
IOResult ioResult;
|
||||
ioResult.bytes = bytesRead;
|
||||
ioResult.errorCode = errorCode;
|
||||
ioResult.overlapped = overlapped;
|
||||
notifications.append(ioResult);
|
||||
if (notifications.count() >= threshold)
|
||||
emit notificationReceived();
|
||||
}
|
||||
|
||||
signals:
|
||||
void notificationReceived();
|
||||
|
||||
public:
|
||||
int threshold;
|
||||
|
||||
struct IOResult
|
||||
{
|
||||
IOResult()
|
||||
: bytes(0), errorCode(ERROR_SUCCESS), overlapped(0)
|
||||
{}
|
||||
DWORD bytes;
|
||||
DWORD errorCode;
|
||||
OVERLAPPED *overlapped;
|
||||
};
|
||||
|
||||
QList<IOResult> notifications;
|
||||
};
|
||||
|
||||
void tst_QWinOverlappedIoNotifier::initTestCase()
|
||||
{
|
||||
sourceFileInfo.setFile(QFINDTESTDATA("tst_qwinoverlappedionotifier.cpp"));
|
||||
QVERIFY2(sourceFileInfo.exists(), "File tst_qwinoverlappedionotifier.cpp not found.");
|
||||
}
|
||||
|
||||
void tst_QWinOverlappedIoNotifier::readFile_data()
|
||||
{
|
||||
QTest::addColumn<QString>("fileName");
|
||||
QTest::addColumn<int>("readBufferSize");
|
||||
QTest::addColumn<DWORD>("expectedBytesRead");
|
||||
|
||||
QString sourceFileName = QDir::toNativeSeparators(sourceFileInfo.absoluteFilePath());
|
||||
int sourceFileSize = sourceFileInfo.size();
|
||||
|
||||
QTest::newRow("read file, less than available")
|
||||
<< sourceFileName << sourceFileSize / 2 << DWORD(sourceFileSize / 2);
|
||||
QTest::newRow("read file, more than available")
|
||||
<< sourceFileName << sourceFileSize * 2 << DWORD(sourceFileSize);
|
||||
}
|
||||
|
||||
void tst_QWinOverlappedIoNotifier::readFile()
|
||||
{
|
||||
QFETCH(QString, fileName);
|
||||
QFETCH(int, readBufferSize);
|
||||
QFETCH(DWORD, expectedBytesRead);
|
||||
|
||||
QWinOverlappedIoNotifier notifier;
|
||||
NotifierSink sink(¬ifier);
|
||||
connect(&sink, &NotifierSink::notificationReceived, &QTestEventLoop::instance(), &QTestEventLoop::exitLoop);
|
||||
|
||||
HANDLE hFile = CreateFile(reinterpret_cast<const wchar_t*>(fileName.utf16()),
|
||||
GENERIC_READ, FILE_SHARE_READ,
|
||||
NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
|
||||
notifier.setHandle(hFile);
|
||||
notifier.setEnabled(true);
|
||||
|
||||
OVERLAPPED overlapped;
|
||||
ZeroMemory(&overlapped, sizeof(OVERLAPPED));
|
||||
QByteArray buffer(readBufferSize, 0);
|
||||
BOOL readSuccess = ReadFile(hFile, buffer.data(), buffer.size(), NULL, &overlapped);
|
||||
QVERIFY(readSuccess || GetLastError() == ERROR_IO_PENDING);
|
||||
|
||||
QTestEventLoop::instance().enterLoop(3);
|
||||
CloseHandle(hFile);
|
||||
QCOMPARE(sink.notifications.count(), 1);
|
||||
QCOMPARE(sink.notifications.last().bytes, expectedBytesRead);
|
||||
QCOMPARE(sink.notifications.last().errorCode, DWORD(ERROR_SUCCESS));
|
||||
QCOMPARE(sink.notifications.last().overlapped, &overlapped);
|
||||
}
|
||||
|
||||
void tst_QWinOverlappedIoNotifier::waitForNotified_data()
|
||||
{
|
||||
readFile_data();
|
||||
}
|
||||
|
||||
void tst_QWinOverlappedIoNotifier::waitForNotified()
|
||||
{
|
||||
QFETCH(QString, fileName);
|
||||
QFETCH(int, readBufferSize);
|
||||
QFETCH(DWORD, expectedBytesRead);
|
||||
|
||||
QWinOverlappedIoNotifier notifier;
|
||||
NotifierSink sink(¬ifier);
|
||||
HANDLE hFile = CreateFile(reinterpret_cast<const wchar_t*>(fileName.utf16()),
|
||||
GENERIC_READ, FILE_SHARE_READ,
|
||||
NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
|
||||
notifier.setHandle(hFile);
|
||||
notifier.setEnabled(true);
|
||||
QCOMPARE(notifier.waitForNotified(100, 0), false);
|
||||
|
||||
OVERLAPPED overlapped;
|
||||
ZeroMemory(&overlapped, sizeof(OVERLAPPED));
|
||||
QByteArray buffer(readBufferSize, 0);
|
||||
BOOL readSuccess = ReadFile(hFile, buffer.data(), buffer.size(), NULL, &overlapped);
|
||||
QVERIFY(readSuccess || GetLastError() == ERROR_IO_PENDING);
|
||||
|
||||
QCOMPARE(notifier.waitForNotified(3000, &overlapped), true);
|
||||
CloseHandle(hFile);
|
||||
QCOMPARE(sink.notifications.count(), 1);
|
||||
QCOMPARE(sink.notifications.last().bytes, expectedBytesRead);
|
||||
QCOMPARE(sink.notifications.last().errorCode, DWORD(ERROR_SUCCESS));
|
||||
QCOMPARE(sink.notifications.last().overlapped, &overlapped);
|
||||
QCOMPARE(notifier.waitForNotified(100, &overlapped), false);
|
||||
}
|
||||
|
||||
void tst_QWinOverlappedIoNotifier::waitForAnyNotified()
|
||||
{
|
||||
const QString fileName = QDir::toNativeSeparators(sourceFileInfo.absoluteFilePath());
|
||||
const int readBufferSize = sourceFileInfo.size();
|
||||
|
||||
QWinOverlappedIoNotifier notifier;
|
||||
HANDLE hFile = CreateFile(reinterpret_cast<const wchar_t*>(fileName.utf16()),
|
||||
GENERIC_READ, FILE_SHARE_READ,
|
||||
NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
|
||||
notifier.setHandle(hFile);
|
||||
notifier.setEnabled(true);
|
||||
QVERIFY(!notifier.waitForAnyNotified(100));
|
||||
|
||||
OVERLAPPED overlapped1;
|
||||
ZeroMemory(&overlapped1, sizeof(OVERLAPPED));
|
||||
QByteArray buffer1(readBufferSize, 0);
|
||||
BOOL readSuccess = ReadFile(hFile, buffer1.data(), buffer1.size(), NULL, &overlapped1);
|
||||
QVERIFY(readSuccess || GetLastError() == ERROR_IO_PENDING);
|
||||
|
||||
OVERLAPPED overlapped2;
|
||||
ZeroMemory(&overlapped2, sizeof(OVERLAPPED));
|
||||
QByteArray buffer2(readBufferSize, 0);
|
||||
readSuccess = ReadFile(hFile, buffer2.data(), buffer2.size(), NULL, &overlapped2);
|
||||
QVERIFY(readSuccess || GetLastError() == ERROR_IO_PENDING);
|
||||
|
||||
QSet<OVERLAPPED *> overlappedObjects;
|
||||
overlappedObjects << &overlapped1 << &overlapped2;
|
||||
|
||||
for (int i = 1; i <= 2; ++i) {
|
||||
OVERLAPPED *notifiedOverlapped = notifier.waitForAnyNotified(3000);
|
||||
QVERIFY(overlappedObjects.contains(notifiedOverlapped));
|
||||
overlappedObjects.remove(notifiedOverlapped);
|
||||
}
|
||||
|
||||
CloseHandle(hFile);
|
||||
QVERIFY(overlappedObjects.isEmpty());
|
||||
QVERIFY(!notifier.waitForAnyNotified(100));
|
||||
}
|
||||
|
||||
void tst_QWinOverlappedIoNotifier::brokenPipe()
|
||||
{
|
||||
QWinOverlappedIoNotifier notifier;
|
||||
NotifierSink sink(¬ifier);
|
||||
connect(&sink, &NotifierSink::notificationReceived, &QTestEventLoop::instance(), &QTestEventLoop::exitLoop);
|
||||
|
||||
wchar_t pipeName[] = L"\\\\.\\pipe\\tst_QWinOverlappedIoNotifier_brokenPipe";
|
||||
HANDLE hPipe = CreateNamedPipe(pipeName,
|
||||
PIPE_ACCESS_DUPLEX,
|
||||
PIPE_TYPE_BYTE | PIPE_NOWAIT | PIPE_REJECT_REMOTE_CLIENTS,
|
||||
1, 0, 0, 0, NULL);
|
||||
QVERIFY(hPipe != INVALID_HANDLE_VALUE);
|
||||
HANDLE hReadEnd = CreateFile(pipeName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
|
||||
QVERIFY(hReadEnd != INVALID_HANDLE_VALUE);
|
||||
notifier.setHandle(hReadEnd);
|
||||
notifier.setEnabled(true);
|
||||
|
||||
OVERLAPPED overlapped;
|
||||
ZeroMemory(&overlapped, sizeof(OVERLAPPED));
|
||||
QByteArray buffer(1024, 0);
|
||||
BOOL readSuccess = ReadFile(hReadEnd, buffer.data(), buffer.size(), NULL, &overlapped);
|
||||
QVERIFY(readSuccess || GetLastError() == ERROR_IO_PENDING);
|
||||
|
||||
// close the write end of the pipe
|
||||
CloseHandle(hPipe);
|
||||
|
||||
QTestEventLoop::instance().enterLoop(3);
|
||||
CloseHandle(hReadEnd);
|
||||
QCOMPARE(sink.notifications.count(), 1);
|
||||
QCOMPARE(sink.notifications.last().bytes, DWORD(0));
|
||||
QCOMPARE(sink.notifications.last().errorCode, DWORD(ERROR_BROKEN_PIPE));
|
||||
QCOMPARE(sink.notifications.last().overlapped, &overlapped);
|
||||
}
|
||||
|
||||
void tst_QWinOverlappedIoNotifier::multipleOperations()
|
||||
{
|
||||
QWinOverlappedIoNotifier clientNotifier;
|
||||
NotifierSink sink(&clientNotifier);
|
||||
sink.threshold = 2;
|
||||
connect(&sink, &NotifierSink::notificationReceived,
|
||||
&QTestEventLoop::instance(), &QTestEventLoop::exitLoop);
|
||||
|
||||
wchar_t pipeName[] = L"\\\\.\\pipe\\tst_QWinOverlappedIoNotifier_multipleOperations";
|
||||
HANDLE hServer = CreateNamedPipe(pipeName,
|
||||
PIPE_ACCESS_DUPLEX,
|
||||
PIPE_TYPE_BYTE | PIPE_NOWAIT | PIPE_REJECT_REMOTE_CLIENTS,
|
||||
1, 0, 0, 0, NULL);
|
||||
QVERIFY(hServer != INVALID_HANDLE_VALUE);
|
||||
HANDLE hClient = CreateFile(pipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL,
|
||||
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
|
||||
QVERIFY(hClient != INVALID_HANDLE_VALUE);
|
||||
clientNotifier.setHandle(hClient);
|
||||
clientNotifier.setEnabled(true);
|
||||
|
||||
// start async read on client
|
||||
QByteArray clientReadBuffer(377, Qt::Uninitialized);
|
||||
OVERLAPPED clientReadOverlapped;
|
||||
ZeroMemory(&clientReadOverlapped, sizeof(clientReadOverlapped));
|
||||
BOOL readSuccess = ReadFile(hClient, clientReadBuffer.data(), clientReadBuffer.size(),
|
||||
NULL, &clientReadOverlapped);
|
||||
QVERIFY(readSuccess || GetLastError() == ERROR_IO_PENDING);
|
||||
|
||||
// start async write client -> server
|
||||
QByteArray clientDataToWrite(233, 'B');
|
||||
OVERLAPPED clientWriteOverlapped;
|
||||
ZeroMemory(&clientWriteOverlapped, sizeof(clientWriteOverlapped));
|
||||
BOOL writeSuccess = WriteFile(hClient, clientDataToWrite.data(), clientDataToWrite.size(),
|
||||
NULL, &clientWriteOverlapped);
|
||||
QVERIFY(writeSuccess || GetLastError() == ERROR_IO_PENDING);
|
||||
|
||||
// start async write server -> client
|
||||
QByteArray serverDataToWrite(144, 'A');
|
||||
OVERLAPPED serverOverlapped;
|
||||
ZeroMemory(&serverOverlapped, sizeof(serverOverlapped));
|
||||
writeSuccess = WriteFile(hServer, serverDataToWrite.data(), serverDataToWrite.size(),
|
||||
NULL, &serverOverlapped);
|
||||
QVERIFY(writeSuccess || GetLastError() == ERROR_IO_PENDING);
|
||||
|
||||
// read synchronously on server to complete the client -> server write
|
||||
QByteArray serverReadBuffer(610, Qt::Uninitialized);
|
||||
DWORD dwBytesRead = 0;
|
||||
readSuccess = ReadFile(hServer, serverReadBuffer.data(), serverReadBuffer.size(),
|
||||
&dwBytesRead, NULL);
|
||||
QVERIFY(readSuccess);
|
||||
QCOMPARE(int(dwBytesRead), clientDataToWrite.size());
|
||||
serverReadBuffer.resize(dwBytesRead);
|
||||
QCOMPARE(serverReadBuffer, clientDataToWrite);
|
||||
|
||||
QTestEventLoop::instance().enterLoop(3);
|
||||
QTRY_COMPARE(sink.notifications.count(), 2);
|
||||
foreach (const NotifierSink::IOResult &r, sink.notifications) {
|
||||
QCOMPARE(r.errorCode, DWORD(ERROR_SUCCESS));
|
||||
if (r.bytes == DWORD(serverDataToWrite.count()))
|
||||
QCOMPARE(r.overlapped, &clientReadOverlapped);
|
||||
else if (r.bytes == DWORD(clientDataToWrite.count()))
|
||||
QCOMPARE(r.overlapped, &clientWriteOverlapped);
|
||||
else
|
||||
QVERIFY2(false, "Unexpected number of bytes received.");
|
||||
}
|
||||
|
||||
CloseHandle(hClient);
|
||||
CloseHandle(hServer);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QWinOverlappedIoNotifier)
|
||||
|
||||
#include "tst_qwinoverlappedionotifier.moc"
|
Loading…
x
Reference in New Issue
Block a user