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 {
|
!winrt {
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
io/qwindowspipereader_p.h \
|
io/qwindowspipereader_p.h \
|
||||||
io/qwindowspipewriter_p.h \
|
io/qwindowspipewriter_p.h
|
||||||
io/qwinoverlappedionotifier_p.h
|
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
io/qsettings_win.cpp \
|
io/qsettings_win.cpp \
|
||||||
io/qstandardpaths_win.cpp \
|
io/qstandardpaths_win.cpp \
|
||||||
io/qstorageinfo_win.cpp \
|
io/qstorageinfo_win.cpp \
|
||||||
io/qwindowspipereader.cpp \
|
io/qwindowspipereader.cpp \
|
||||||
io/qwindowspipewriter.cpp \
|
io/qwindowspipewriter.cpp
|
||||||
io/qwinoverlappedionotifier.cpp
|
|
||||||
|
|
||||||
LIBS += -lmpr
|
LIBS += -lmpr
|
||||||
} else {
|
} 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 \
|
qurl \
|
||||||
qurlinternal \
|
qurlinternal \
|
||||||
qurlquery \
|
qurlquery \
|
||||||
qwinoverlappedionotifier \
|
|
||||||
|
|
||||||
!win32 {
|
|
||||||
SUBDIRS -=\
|
|
||||||
qwinoverlappedionotifier
|
|
||||||
}
|
|
||||||
|
|
||||||
!qtHaveModule(gui): SUBDIRS -= \
|
!qtHaveModule(gui): SUBDIRS -= \
|
||||||
qdatastream \
|
qdatastream \
|
||||||
@ -73,5 +67,4 @@ win32:!qtConfig(private_tests): SUBDIRS -= \
|
|||||||
qprocess-noapplication
|
qprocess-noapplication
|
||||||
|
|
||||||
winrt: SUBDIRS -= \
|
winrt: SUBDIRS -= \
|
||||||
qstorageinfo \
|
qstorageinfo
|
||||||
qwinoverlappedionotifier
|
|
||||||
|
@ -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