Warning: That file was not part of the compilation database. It may have many parsing errors.

1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qwindowspipewriter_p.h"
41#include "qiodevice_p.h"
42#include <qscopedvaluerollback.h>
43
44QT_BEGIN_NAMESPACE
45
46QWindowsPipeWriter::Overlapped::Overlapped(QWindowsPipeWriter *pipeWriter)
47 : pipeWriter(pipeWriter)
48{
49}
50
51void QWindowsPipeWriter::Overlapped::clear()
52{
53 ZeroMemory(this, sizeof(OVERLAPPED));
54}
55
56
57QWindowsPipeWriter::QWindowsPipeWriter(HANDLE pipeWriteEnd, QObject *parent)
58 : QObject(parent),
59 handle(pipeWriteEnd),
60 overlapped(nullptr),
61 pendingBytesWrittenValue(0),
62 stopped(true),
63 writeSequenceStarted(false),
64 notifiedCalled(false),
65 bytesWrittenPending(false),
66 inBytesWritten(false)
67{
68 connect(this, &QWindowsPipeWriter::_q_queueBytesWritten,
69 this, &QWindowsPipeWriter::emitPendingBytesWrittenValue, Qt::QueuedConnection);
70}
71
72QWindowsPipeWriter::~QWindowsPipeWriter()
73{
74 stop();
75 delete overlapped;
76}
77
78bool QWindowsPipeWriter::waitForWrite(int msecs)
79{
80 if (bytesWrittenPending) {
81 emitPendingBytesWrittenValue();
82 return true;
83 }
84
85 if (!writeSequenceStarted)
86 return false;
87
88 if (!waitForNotification(msecs))
89 return false;
90
91 if (bytesWrittenPending) {
92 emitPendingBytesWrittenValue();
93 return true;
94 }
95
96 return false;
97}
98
99qint64 QWindowsPipeWriter::bytesToWrite() const
100{
101 return buffer.size() + pendingBytesWrittenValue;
102}
103
104void QWindowsPipeWriter::emitPendingBytesWrittenValue()
105{
106 if (bytesWrittenPending) {
107 // Reset the state even if we don't emit bytesWritten().
108 // It's a defined behavior to not re-emit this signal recursively.
109 bytesWrittenPending = false;
110 const qint64 bytes = pendingBytesWrittenValue;
111 pendingBytesWrittenValue = 0;
112
113 emit canWrite();
114 if (!inBytesWritten) {
115 QScopedValueRollback<bool> guard(inBytesWritten, true);
116 emit bytesWritten(bytes);
117 }
118 }
119}
120
121void QWindowsPipeWriter::writeFileCompleted(DWORD errorCode, DWORD numberOfBytesTransfered,
122 OVERLAPPED *overlappedBase)
123{
124 Overlapped *overlapped = static_cast<Overlapped *>(overlappedBase);
125 if (overlapped->pipeWriter)
126 overlapped->pipeWriter->notified(errorCode, numberOfBytesTransfered);
127 else
128 delete overlapped;
129}
130
131/*!
132 \internal
133 Will be called whenever the write operation completes.
134 */
135void QWindowsPipeWriter::notified(DWORD errorCode, DWORD numberOfBytesWritten)
136{
137 notifiedCalled = true;
138 writeSequenceStarted = false;
139 Q_ASSERT(errorCode != ERROR_SUCCESS || numberOfBytesWritten == DWORD(buffer.size()));
140 buffer.clear();
141
142 switch (errorCode) {
143 case ERROR_SUCCESS:
144 break;
145 case ERROR_OPERATION_ABORTED:
146 if (stopped)
147 break;
148 Q_FALLTHROUGH();
149 default:
150 qErrnoWarning(errorCode, "QWindowsPipeWriter: asynchronous write failed.");
151 break;
152 }
153
154 // After the writer was stopped, the only reason why this function can be called is the
155 // completion of a cancellation. No signals should be emitted, and no new write sequence should
156 // be started in this case.
157 if (stopped)
158 return;
159
160 pendingBytesWrittenValue += qint64(numberOfBytesWritten);
161 if (!bytesWrittenPending) {
162 bytesWrittenPending = true;
163 emit _q_queueBytesWritten(QWindowsPipeWriter::QPrivateSignal());
164 }
165}
166
167bool QWindowsPipeWriter::waitForNotification(int timeout)
168{
169 QElapsedTimer t;
170 t.start();
171 notifiedCalled = false;
172 int msecs = timeout;
173 while (SleepEx(msecs == -1 ? INFINITE : msecs, TRUE) == WAIT_IO_COMPLETION) {
174 if (notifiedCalled)
175 return true;
176
177 // Some other I/O completion routine was called. Wait some more.
178 msecs = qt_subtract_from_timeout(timeout, t.elapsed());
179 if (!msecs)
180 break;
181 }
182 return notifiedCalled;
183}
184
185bool QWindowsPipeWriter::write(const QByteArray &ba)
186{
187 if (writeSequenceStarted)
188 return false;
189
190 if (!overlapped)
191 overlapped = new Overlapped(this);
192 overlapped->clear();
193 buffer = ba;
194 stopped = false;
195 writeSequenceStarted = true;
196 if (!WriteFileEx(handle, buffer.constData(), buffer.size(),
197 overlapped, &writeFileCompleted)) {
198 writeSequenceStarted = false;
199 buffer.clear();
200
201 const DWORD errorCode = GetLastError();
202 switch (errorCode) {
203 case ERROR_NO_DATA: // "The pipe is being closed."
204 // The other end has closed the pipe. This can happen in QLocalSocket. Do not warn.
205 break;
206 default:
207 qErrnoWarning(errorCode, "QWindowsPipeWriter::write failed.");
208 }
209 return false;
210 }
211
212 return true;
213}
214
215void QWindowsPipeWriter::stop()
216{
217 stopped = true;
218 bytesWrittenPending = false;
219 pendingBytesWrittenValue = 0;
220 if (writeSequenceStarted) {
221 overlapped->pipeWriter = nullptr;
222 if (!CancelIoEx(handle, overlapped)) {
223 const DWORD dwError = GetLastError();
224 if (dwError != ERROR_NOT_FOUND) {
225 qErrnoWarning(dwError, "QWindowsPipeWriter: CancelIoEx on handle %p failed.",
226 handle);
227 }
228 }
229 overlapped = nullptr; // The object will be deleted in the I/O callback.
230 writeSequenceStarted = false;
231 }
232}
233
234QT_END_NAMESPACE
235

Warning: That file was not part of the compilation database. It may have many parsing errors.