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 | |
44 | QT_BEGIN_NAMESPACE |
45 | |
46 | QWindowsPipeWriter::Overlapped::Overlapped(QWindowsPipeWriter *pipeWriter) |
47 | : pipeWriter(pipeWriter) |
48 | { |
49 | } |
50 | |
51 | void QWindowsPipeWriter::Overlapped::clear() |
52 | { |
53 | ZeroMemory(this, sizeof(OVERLAPPED)); |
54 | } |
55 | |
56 | |
57 | QWindowsPipeWriter::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 | |
72 | QWindowsPipeWriter::~QWindowsPipeWriter() |
73 | { |
74 | stop(); |
75 | delete overlapped; |
76 | } |
77 | |
78 | bool 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 | |
99 | qint64 QWindowsPipeWriter::bytesToWrite() const |
100 | { |
101 | return buffer.size() + pendingBytesWrittenValue; |
102 | } |
103 | |
104 | void 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 | |
121 | void 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 | */ |
135 | void 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 | |
167 | bool 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 | |
185 | bool 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 | |
215 | void 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 | |
234 | QT_END_NAMESPACE |
235 |
Warning: That file was not part of the compilation database. It may have many parsing errors.