18 handle(INVALID_HANDLE_VALUE),
19 eventHandle(CreateEvent(NULL, FALSE, FALSE, NULL)),
20 syncHandle(CreateEvent(NULL, TRUE, FALSE, NULL)),
23 actualReadBufferSize(0),
25 lastError(ERROR_SUCCESS),
27 readSequenceStarted(
false),
29 readyReadPending(
false),
30 winEventActPosted(
false)
32 ZeroMemory(&overlapped,
sizeof(OVERLAPPED));
33 overlapped.hEvent = eventHandle;
34 waitObject = CreateThreadpoolWait(waitCallback,
this, NULL);
35 if (waitObject == NULL)
36 qErrnoWarning(
"QWindowsPipeReader: CreateThreadpollWait failed.");
45 WaitForThreadpoolWaitCallbacks(waitObject, FALSE);
46 CloseThreadpoolWait(waitObject);
47 CloseHandle(eventHandle);
48 CloseHandle(syncHandle);
58 actualReadBufferSize = 0;
59 readyReadPending =
false;
63 lastError = ERROR_SUCCESS;
72 cancelAsyncRead(Stopped);
82 cancelAsyncRead(Draining);
92 cancelAsyncRead(Stopped);
94 actualReadBufferSize = 0;
98 lastError = ERROR_SUCCESS;
106 if (state != Running)
111 if (readSequenceStarted) {
115 if (!CancelIoEx(
handle, &overlapped)) {
116 const DWORD dwError = GetLastError();
117 if (dwError != ERROR_NOT_FOUND) {
118 qErrnoWarning(dwError,
"QWindowsPipeReader: CancelIoEx on handle %p failed.",
126 waitForNotification();
128 }
while (readSequenceStarted);
144 readBufferMaxSize =
size;
154 return readSequenceStarted || readyReadPending
155 || (lastError != ERROR_SUCCESS && !pipeBroken);
163 return actualReadBufferSize;
175 if (maxlen == 1 && actualReadBufferSize > 0) {
177 actualReadBufferSize--;
181 actualReadBufferSize -= readSoFar;
185 startAsyncReadHelper(&locker);
203 if (actualReadBufferSize > 0) {
205 actualReadBufferSize -= readSoFar;
209 startAsyncReadHelper(&locker);
225 actualReadBufferSize -= skippedSoFar;
228 startAsyncReadHelper(&locker);
229 if (skippedSoFar == 0)
242 return readBuffer.indexOf(
'\n', actualReadBufferSize) >= 0;
251 startAsyncReadHelper(&locker);
256 if (readSequenceStarted || lastError != ERROR_SUCCESS)
260 startAsyncReadLocked();
263 if (!readyReadPending && lastError == ERROR_SUCCESS)
266 if (!winEventActPosted) {
267 winEventActPosted =
true;
274 SetEvent(syncHandle);
281void QWindowsPipeReader::startAsyncReadLocked()
287 if (bytesToRead == 0)
290 while (lastError == ERROR_SUCCESS) {
291 if (readBufferMaxSize && bytesToRead > (readBufferMaxSize -
readBuffer.size())) {
292 bytesToRead = readBufferMaxSize -
readBuffer.size();
293 if (bytesToRead <= 0) {
305 DWORD numberOfBytesRead;
306 DWORD errorCode = ERROR_SUCCESS;
307 if (!ReadFile(
handle,
ptr, bytesToRead, &numberOfBytesRead, &overlapped)) {
308 errorCode = GetLastError();
309 if (errorCode == ERROR_IO_PENDING) {
312 readSequenceStarted =
true;
313 SetThreadpoolWait(waitObject, eventHandle, NULL);
318 if (!readCompleted(errorCode, numberOfBytesRead))
323 if (state == Draining) {
341void QWindowsPipeReader::waitCallback(PTP_CALLBACK_INSTANCE instance, PVOID
context,
342 PTP_WAIT wait, TP_WAIT_RESULT waitResult)
350 DWORD numberOfBytesTransfered = 0;
351 DWORD errorCode = ERROR_SUCCESS;
352 if (!GetOverlappedResult(pipeReader->handle, &pipeReader->overlapped,
353 &numberOfBytesTransfered, FALSE))
354 errorCode = GetLastError();
356 pipeReader->mutex.
lock();
358 pipeReader->readSequenceStarted =
false;
365 if (pipeReader->lastError == ERROR_SUCCESS && pipeReader->state != Stopped) {
368 if (pipeReader->state == Draining && errorCode == ERROR_OPERATION_ABORTED)
369 errorCode = ERROR_SUCCESS;
371 if (pipeReader->readCompleted(errorCode, numberOfBytesTransfered))
372 pipeReader->startAsyncReadLocked();
374 if (pipeReader->state == Running && !pipeReader->winEventActPosted) {
375 pipeReader->winEventActPosted =
true;
376 pipeReader->mutex.
unlock();
379 pipeReader->mutex.
unlock();
382 pipeReader->mutex.
unlock();
387 SetEvent(pipeReader->syncHandle);
394bool QWindowsPipeReader::readCompleted(DWORD errorCode, DWORD numberOfBytesRead)
399 if (errorCode == ERROR_SUCCESS || errorCode == ERROR_MORE_DATA) {
400 readyReadPending =
true;
401 pendingReadBytes += numberOfBytesRead;
402 readBuffer.truncate(actualReadBufferSize + pendingReadBytes);
406 lastError = errorCode;
416 consumePendingAndEmit(
true);
426bool QWindowsPipeReader::consumePendingAndEmit(
bool allowWinActPosting)
428 ResetEvent(syncHandle);
432 if (allowWinActPosting)
433 winEventActPosted =
false;
435 const bool emitReadyRead = consumePending();
436 const DWORD dwError = lastError;
444 const bool emitPipeClosed = (dwError != ERROR_SUCCESS && !pipeBroken);
451 if (state != Running)
454 if (!emitPipeClosed) {
461 if (alive && dwError != ERROR_BROKEN_PIPE && dwError != ERROR_PIPE_NOT_CONNECTED)
462 emit winError(dwError,
"QWindowsPipeReader::consumePendingAndEmit"_L1);
467 return emitReadyRead;
474bool QWindowsPipeReader::consumePending()
476 if (readyReadPending) {
477 readyReadPending =
false;
478 actualReadBufferSize += pendingReadBytes;
479 pendingReadBytes = 0;
492 if (PeekNamedPipe(
handle,
nullptr, 0,
nullptr, &bytes,
nullptr))
495 lastError = GetLastError();
499bool QWindowsPipeReader::waitForNotification()
503 waitRet = WaitForSingleObjectEx(syncHandle, INFINITE, TRUE);
504 if (waitRet == WAIT_OBJECT_0)
508 }
while (waitRet == WAIT_IO_COMPLETION);
515#include "moc_qwindowspipereader_p.cpp"
static void postEvent(QObject *receiver, QEvent *event, int priority=Qt::NormalEventPriority)
void unlock() noexcept
Unlocks this mutex locker.
void unlock() noexcept
Unlocks the mutex.
void lock() noexcept
Locks the mutex.
virtual bool event(QEvent *event)
This virtual function receives events to an object and should return true if the event e was recogniz...
void stop()
Stops the asynchronous read sequence.
bool canReadLine() const
Returns true if a complete line of data can be read from the buffer.
qint64 bytesAvailable() const
Returns the number of bytes we've read so far.
DWORD checkPipeState()
Returns the number of available bytes in the pipe.
bool isReadOperationActive() const
Returns true if async operation is in progress, there is pending data to read, or a read error is pen...
qint64 skip(qint64 maxlen)
Skips up to {maxlen} bytes from the internal read buffer.
QWindowsPipeReader(QObject *parent=nullptr)
void startAsyncRead()
Starts an asynchronous read sequence on the pipe.
void stopAndClear()
Stops the asynchronous read sequence.
void drainAndStop()
Stops the asynchronous read sequence.
qint64 read(char *data, qint64 maxlen)
Copies at most {maxlen} bytes from the internal read buffer to {data}.
qint64 readLine(char *data, qint64 maxlen)
Reads a line from the internal buffer, but no more than {maxlen} characters.
void winError(ulong, const QString &)
void setHandle(HANDLE hPipeReadEnd)
Sets the handle to read from.
void setMaxReadBufferSize(qint64 size)
Sets the size of internal read buffer.
bool event(QEvent *e) override
Receives notification that the read operation has completed.
void newState(QList< State > &states, const char *token, const char *lexem, bool pre)
void qErrnoWarning(const char *msg,...)
Combined button and popup list for selecting options.
static ControlElement< T > * ptr(QWidget *widget)
constexpr const T & qMin(const T &a, const T &b)
constexpr const T & qMax(const T &a, const T &b)
GLuint64 GLenum void * handle
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLbitfield GLuint readBuffer
static const DWORD minReadBufferSize
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent