summaryrefslogtreecommitdiffstats
path: root/src/corelib/io/qwindowspipewriter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/io/qwindowspipewriter.cpp')
-rw-r--r--src/corelib/io/qwindowspipewriter.cpp239
1 files changed, 136 insertions, 103 deletions
diff --git a/src/corelib/io/qwindowspipewriter.cpp b/src/corelib/io/qwindowspipewriter.cpp
index c7144d2c6b..79e7d13eb5 100644
--- a/src/corelib/io/qwindowspipewriter.cpp
+++ b/src/corelib/io/qwindowspipewriter.cpp
@@ -38,144 +38,177 @@
****************************************************************************/
#include "qwindowspipewriter_p.h"
+#include "qiodevice_p.h"
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_THREAD
+extern bool qt_cancelIo(HANDLE handle, OVERLAPPED *overlapped); // from qwindowspipereader.cpp
-QWindowsPipeWriter::QWindowsPipeWriter(HANDLE pipe, QObject * parent)
- : QThread(parent),
- writePipe(INVALID_HANDLE_VALUE),
- quitNow(false),
- hasWritten(false)
+
+QWindowsPipeWriter::Overlapped::Overlapped(QWindowsPipeWriter *pipeWriter)
+ : pipeWriter(pipeWriter)
+{
+}
+
+void QWindowsPipeWriter::Overlapped::clear()
{
- DuplicateHandle(GetCurrentProcess(), pipe, GetCurrentProcess(),
- &writePipe, 0, FALSE, DUPLICATE_SAME_ACCESS);
+ ZeroMemory(this, sizeof(OVERLAPPED));
+}
+
+
+QWindowsPipeWriter::QWindowsPipeWriter(HANDLE pipeWriteEnd, QObject *parent)
+ : QObject(parent),
+ handle(pipeWriteEnd),
+ overlapped(this),
+ numberOfBytesToWrite(0),
+ pendingBytesWrittenValue(0),
+ stopped(true),
+ writeSequenceStarted(false),
+ notifiedCalled(false),
+ bytesWrittenPending(false),
+ inBytesWritten(false)
+{
+ connect(this, &QWindowsPipeWriter::_q_queueBytesWritten,
+ this, &QWindowsPipeWriter::emitPendingBytesWrittenValue, Qt::QueuedConnection);
}
QWindowsPipeWriter::~QWindowsPipeWriter()
{
- lock.lock();
- quitNow = true;
- waitCondition.wakeOne();
- lock.unlock();
- if (!wait(30000))
- terminate();
- CloseHandle(writePipe);
+ stop();
}
bool QWindowsPipeWriter::waitForWrite(int msecs)
{
- QMutexLocker locker(&lock);
- bool hadWritten = hasWritten;
- hasWritten = false;
- if (hadWritten)
+ if (!writeSequenceStarted)
+ return false;
+
+ if (bytesWrittenPending) {
+ if (!inBytesWritten)
+ emitPendingBytesWrittenValue();
return true;
- if (!waitCondition.wait(&lock, msecs))
+ }
+
+ if (!waitForNotification(msecs))
return false;
- hadWritten = hasWritten;
- hasWritten = false;
- return hadWritten;
+
+ if (bytesWrittenPending) {
+ if (!inBytesWritten)
+ emitPendingBytesWrittenValue();
+ return true;
+ }
+
+ return false;
}
-qint64 QWindowsPipeWriter::write(const char *ptr, qint64 maxlen)
+qint64 QWindowsPipeWriter::bytesToWrite() const
{
- if (!isRunning())
- return -1;
-
- QMutexLocker locker(&lock);
- data.append(ptr, maxlen);
- waitCondition.wakeOne();
- return maxlen;
+ return numberOfBytesToWrite;
}
-class QPipeWriterOverlapped
+void QWindowsPipeWriter::emitPendingBytesWrittenValue()
{
-public:
- QPipeWriterOverlapped()
- {
- overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (bytesWrittenPending) {
+ bytesWrittenPending = false;
+ const qint64 bytes = pendingBytesWrittenValue;
+ pendingBytesWrittenValue = 0;
+
+ inBytesWritten = true;
+ emit bytesWritten(bytes);
+ inBytesWritten = false;
+ emit canWrite();
}
+}
- ~QPipeWriterOverlapped()
- {
- CloseHandle(overlapped.hEvent);
- }
+void QWindowsPipeWriter::writeFileCompleted(DWORD errorCode, DWORD numberOfBytesTransfered,
+ OVERLAPPED *overlappedBase)
+{
+ Overlapped *overlapped = static_cast<Overlapped *>(overlappedBase);
+ overlapped->pipeWriter->notified(errorCode, numberOfBytesTransfered);
+}
- void prepare()
- {
- const HANDLE hEvent = overlapped.hEvent;
- ZeroMemory(&overlapped, sizeof overlapped);
- overlapped.hEvent = hEvent;
+/*!
+ \internal
+ Will be called whenever the write operation completes.
+ */
+void QWindowsPipeWriter::notified(DWORD errorCode, DWORD numberOfBytesWritten)
+{
+ notifiedCalled = true;
+ writeSequenceStarted = false;
+ numberOfBytesToWrite = 0;
+
+ switch (errorCode) {
+ case ERROR_SUCCESS:
+ break;
+ case ERROR_OPERATION_ABORTED:
+ if (stopped)
+ break;
+ // fall through
+ default:
+ qErrnoWarning(errorCode, "QWindowsPipeWriter: asynchronous write failed.");
+ break;
}
- OVERLAPPED *operator&()
- {
- return &overlapped;
+ // After the writer was stopped, the only reason why this function can be called is the
+ // completion of a cancellation. No signals should be emitted, and no new write sequence should
+ // be started in this case.
+ if (stopped)
+ return;
+
+ pendingBytesWrittenValue += qint64(numberOfBytesWritten);
+ if (!bytesWrittenPending) {
+ bytesWrittenPending = true;
+ emit _q_queueBytesWritten(QWindowsPipeWriter::QPrivateSignal());
}
+}
-private:
- OVERLAPPED overlapped;
-};
+bool QWindowsPipeWriter::waitForNotification(int timeout)
+{
+ QElapsedTimer t;
+ t.start();
+ notifiedCalled = false;
+ int msecs = timeout;
+ while (SleepEx(msecs == -1 ? INFINITE : msecs, TRUE) == WAIT_IO_COMPLETION) {
+ if (notifiedCalled)
+ return true;
+
+ // Some other I/O completion routine was called. Wait some more.
+ msecs = qt_subtract_from_timeout(timeout, t.elapsed());
+ if (!msecs)
+ break;
+ }
+ return notifiedCalled;
+}
-void QWindowsPipeWriter::run()
+qint64 QWindowsPipeWriter::write(const char *ptr, qint64 maxlen)
{
- QPipeWriterOverlapped overl;
- forever {
- lock.lock();
- while(data.isEmpty() && (!quitNow)) {
- waitCondition.wakeOne();
- waitCondition.wait(&lock);
- }
+ if (writeSequenceStarted)
+ return 0;
+
+ overlapped.clear();
+ numberOfBytesToWrite = maxlen;
+ stopped = false;
+ writeSequenceStarted = true;
+ if (!WriteFileEx(handle, ptr, maxlen, &overlapped, &writeFileCompleted)) {
+ writeSequenceStarted = false;
+ qErrnoWarning("QWindowsPipeWriter::write failed.");
+ }
- if (quitNow) {
- lock.unlock();
- quitNow = false;
- break;
- }
+ return maxlen;
+}
- QByteArray copy = data;
-
- lock.unlock();
-
- const char *ptrData = copy.data();
- qint64 maxlen = copy.size();
- qint64 totalWritten = 0;
- overl.prepare();
- while ((!quitNow) && totalWritten < maxlen) {
- DWORD written = 0;
- if (!WriteFile(writePipe, ptrData + totalWritten,
- maxlen - totalWritten, &written, &overl)) {
- const DWORD writeError = GetLastError();
- if (writeError == 0xE8/*NT_STATUS_INVALID_USER_BUFFER*/) {
- // give the os a rest
- msleep(100);
- continue;
- }
- if (writeError != ERROR_IO_PENDING) {
- qErrnoWarning(writeError, "QWindowsPipeWriter: async WriteFile failed.");
- return;
- }
- if (!GetOverlappedResult(writePipe, &overl, &written, TRUE)) {
- qErrnoWarning(GetLastError(), "QWindowsPipeWriter: GetOverlappedResult failed.");
- return;
- }
+void QWindowsPipeWriter::stop()
+{
+ stopped = true;
+ if (writeSequenceStarted) {
+ if (!qt_cancelIo(handle, &overlapped)) {
+ const DWORD dwError = GetLastError();
+ if (dwError != ERROR_NOT_FOUND) {
+ qErrnoWarning(dwError, "QWindowsPipeWriter: qt_cancelIo on handle %x failed.",
+ handle);
}
- totalWritten += written;
-#if defined QPIPEWRITER_DEBUG
- qDebug("QWindowsPipeWriter::run() wrote %d %d/%d bytes",
- written, int(totalWritten), int(maxlen));
-#endif
- lock.lock();
- data.remove(0, written);
- hasWritten = true;
- lock.unlock();
}
- emit bytesWritten(totalWritten);
- emit canWrite();
+ waitForNotification(-1);
}
}
-#endif //QT_NO_THREAD
-
QT_END_NAMESPACE