Line | Source Code | Coverage |
---|
1 | /**************************************************************************** | - |
2 | ** | - |
3 | ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). | - |
4 | ** Contact: http://www.qt-project.org/legal | - |
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 Digia. For licensing terms and | - |
14 | ** conditions see http://qt.digia.com/licensing. For further information | - |
15 | ** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software | - |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the | - |
21 | ** packaging of this file. Please review the following information to | - |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements | - |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | - |
24 | ** | - |
25 | ** In addition, as a special exception, Digia gives you certain additional | - |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception | - |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | - |
28 | ** | - |
29 | ** GNU General Public License Usage | - |
30 | ** Alternatively, this file may be used under the terms of the GNU | - |
31 | ** General Public License version 3.0 as published by the Free Software | - |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the | - |
33 | ** packaging of this file. Please review the following information to | - |
34 | ** ensure the GNU General Public License version 3.0 requirements will be | - |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. | - |
36 | ** | - |
37 | ** | - |
38 | ** $QT_END_LICENSE$ | - |
39 | ** | - |
40 | ****************************************************************************/ | - |
41 | | - |
42 | #include "qsocketnotifier.h" | - |
43 | | - |
44 | #include "qplatformdefs.h" | - |
45 | | - |
46 | #include "qabstracteventdispatcher.h" | - |
47 | #include "qcoreapplication.h" | - |
48 | | - |
49 | #include "qobject_p.h" | - |
50 | #include <private/qthread_p.h> | - |
51 | | - |
52 | QT_BEGIN_NAMESPACE | - |
53 | | - |
54 | class QSocketNotifierPrivate : public QObjectPrivate | - |
55 | { | - |
56 | Q_DECLARE_PUBLIC(QSocketNotifier) | - |
57 | public: | - |
58 | qintptr sockfd; | - |
59 | QSocketNotifier::Type sntype; | - |
60 | bool snenabled; | - |
61 | }; | - |
62 | | - |
63 | /*! | - |
64 | \class QSocketNotifier | - |
65 | \inmodule QtCore | - |
66 | \brief The QSocketNotifier class provides support for monitoring | - |
67 | activity on a file descriptor. | - |
68 | | - |
69 | \ingroup network | - |
70 | \ingroup io | - |
71 | | - |
72 | The QSocketNotifier makes it possible to integrate Qt's event | - |
73 | loop with other event loops based on file descriptors. File | - |
74 | descriptor action is detected in Qt's main event | - |
75 | loop (QCoreApplication::exec()). | - |
76 | | - |
77 | \target write notifiers | - |
78 | | - |
79 | Once you have opened a device using a low-level (usually | - |
80 | platform-specific) API, you can create a socket notifier to | - |
81 | monitor the file descriptor. The socket notifier is enabled by | - |
82 | default, i.e. it emits the activated() signal whenever a socket | - |
83 | event corresponding to its type occurs. Connect the activated() | - |
84 | signal to the slot you want to be called when an event | - |
85 | corresponding to your socket notifier's type occurs. | - |
86 | | - |
87 | There are three types of socket notifiers: read, write, and | - |
88 | exception. The type is described by the \l Type enum, and must be | - |
89 | specified when constructing the socket notifier. After | - |
90 | construction it can be determined using the type() function. Note | - |
91 | that if you need to monitor both reads and writes for the same | - |
92 | file descriptor, you must create two socket notifiers. Note also | - |
93 | that it is not possible to install two socket notifiers of the | - |
94 | same type (\l Read, \l Write, \l Exception) on the same socket. | - |
95 | | - |
96 | The setEnabled() function allows you to disable as well as enable | - |
97 | the socket notifier. It is generally advisable to explicitly | - |
98 | enable or disable the socket notifier, especially for write | - |
99 | notifiers. A disabled notifier ignores socket events (the same | - |
100 | effect as not creating the socket notifier). Use the isEnabled() | - |
101 | function to determine the notifier's current status. | - |
102 | | - |
103 | Finally, you can use the socket() function to retrieve the | - |
104 | socket identifier. Although the class is called QSocketNotifier, | - |
105 | it is normally used for other types of devices than sockets. | - |
106 | QTcpSocket and QUdpSocket provide notification through signals, so | - |
107 | there is normally no need to use a QSocketNotifier on them. | - |
108 | | - |
109 | \section1 Notes for Windows Users | - |
110 | | - |
111 | The socket passed to QSocketNotifier will become non-blocking, even if | - |
112 | it was created as a blocking socket. | - |
113 | The activated() signal is sometimes triggered by high general activity | - |
114 | on the host, even if there is nothing to read. A subsequent read from | - |
115 | the socket can then fail, the error indicating that there is no data | - |
116 | available (e.g., \c{WSAEWOULDBLOCK}). This is an operating system | - |
117 | limitation, and not a bug in QSocketNotifier. | - |
118 | | - |
119 | To ensure that the socket notifier handles read notifications correctly, | - |
120 | follow these steps when you receive a notification: | - |
121 | | - |
122 | \list 1 | - |
123 | \li Disable the notifier. | - |
124 | \li Read data from the socket. | - |
125 | \li Re-enable the notifier if you are interested in more data (such as after | - |
126 | having written a new command to a remote server). | - |
127 | \endlist | - |
128 | | - |
129 | To ensure that the socket notifier handles write notifications correctly, | - |
130 | follow these steps when you receive a notification: | - |
131 | | - |
132 | \list 1 | - |
133 | \li Disable the notifier. | - |
134 | \li Write as much data as you can (before \c EWOULDBLOCK is returned). | - |
135 | \li Re-enable notifier if you have more data to write. | - |
136 | \endlist | - |
137 | | - |
138 | \b{Further information:} | - |
139 | On Windows, Qt always disables the notifier after getting a notification, | - |
140 | and only re-enables it if more data is expected. For example, if data is | - |
141 | read from the socket and it can be used to read more, or if reading or | - |
142 | writing is not possible because the socket would block, in which case | - |
143 | it is necessary to wait before attempting to read or write again. | - |
144 | | - |
145 | \sa QFile, QProcess, QTcpSocket, QUdpSocket | - |
146 | */ | - |
147 | | - |
148 | /*! | - |
149 | \enum QSocketNotifier::Type | - |
150 | | - |
151 | This enum describes the various types of events that a socket | - |
152 | notifier can recognize. The type must be specified when | - |
153 | constructing the socket notifier. | - |
154 | | - |
155 | Note that if you need to monitor both reads and writes for the | - |
156 | same file descriptor, you must create two socket notifiers. Note | - |
157 | also that it is not possible to install two socket notifiers of | - |
158 | the same type (Read, Write, Exception) on the same socket. | - |
159 | | - |
160 | \value Read There is data to be read. | - |
161 | \value Write Data can be written. | - |
162 | \value Exception An exception has occurred. We recommend against using this. | - |
163 | | - |
164 | \sa QSocketNotifier(), type() | - |
165 | */ | - |
166 | | - |
167 | /*! | - |
168 | Constructs a socket notifier with the given \a parent. It enables | - |
169 | the \a socket, and watches for events of the given \a type. | - |
170 | | - |
171 | It is generally advisable to explicitly enable or disable the | - |
172 | socket notifier, especially for write notifiers. | - |
173 | | - |
174 | \b{Note for Windows users:} The socket passed to QSocketNotifier | - |
175 | will become non-blocking, even if it was created as a blocking socket. | - |
176 | | - |
177 | \sa setEnabled(), isEnabled() | - |
178 | */ | - |
179 | | - |
180 | QSocketNotifier::QSocketNotifier(qintptr socket, Type type, QObject *parent) | - |
181 | : QObject(*new QSocketNotifierPrivate, parent) | - |
182 | { | - |
183 | Q_D(QSocketNotifier); executed (the execution status of this line is deduced): QSocketNotifierPrivate * const d = d_func(); | - |
184 | if (socket < 0) partially evaluated: socket < 0 no Evaluation Count:0 | yes Evaluation Count:17761 |
| 0-17761 |
185 | qWarning("QSocketNotifier: Invalid socket specified"); never executed: QMessageLogger("kernel/qsocketnotifier.cpp", 185, __PRETTY_FUNCTION__).warning("QSocketNotifier: Invalid socket specified"); | 0 |
186 | d->sockfd = socket; executed (the execution status of this line is deduced): d->sockfd = socket; | - |
187 | d->sntype = type; executed (the execution status of this line is deduced): d->sntype = type; | - |
188 | d->snenabled = true; executed (the execution status of this line is deduced): d->snenabled = true; | - |
189 | | - |
190 | if (!d->threadData->eventDispatcher) { partially evaluated: !d->threadData->eventDispatcher no Evaluation Count:0 | yes Evaluation Count:17761 |
| 0-17761 |
191 | qWarning("QSocketNotifier: Can only be used with threads started with QThread"); never executed (the execution status of this line is deduced): QMessageLogger("kernel/qsocketnotifier.cpp", 191, __PRETTY_FUNCTION__).warning("QSocketNotifier: Can only be used with threads started with QThread"); | - |
192 | } else { | 0 |
193 | d->threadData->eventDispatcher->registerSocketNotifier(this); executed (the execution status of this line is deduced): d->threadData->eventDispatcher->registerSocketNotifier(this); | - |
194 | } executed: } Execution Count:17760 | 17760 |
195 | } | - |
196 | | - |
197 | /*! | - |
198 | Destroys this socket notifier. | - |
199 | */ | - |
200 | | - |
201 | QSocketNotifier::~QSocketNotifier() | - |
202 | { | - |
203 | setEnabled(false); executed (the execution status of this line is deduced): setEnabled(false); | - |
204 | } executed: } Execution Count:18312 | 18312 |
205 | | - |
206 | | - |
207 | /*! | - |
208 | \fn void QSocketNotifier::activated(int socket) | - |
209 | | - |
210 | This signal is emitted whenever the socket notifier is enabled and | - |
211 | a socket event corresponding to its \l {Type}{type} occurs. | - |
212 | | - |
213 | The socket identifier is passed in the \a socket parameter. | - |
214 | | - |
215 | \sa type(), socket() | - |
216 | */ | - |
217 | | - |
218 | | - |
219 | /*! | - |
220 | Returns the socket identifier specified to the constructor. | - |
221 | | - |
222 | \sa type() | - |
223 | */ | - |
224 | qintptr QSocketNotifier::socket() const | - |
225 | { | - |
226 | Q_D(const QSocketNotifier); executed (the execution status of this line is deduced): const QSocketNotifierPrivate * const d = d_func(); | - |
227 | return d->sockfd; executed: return d->sockfd; Execution Count:43694 | 43694 |
228 | } | - |
229 | | - |
230 | /*! | - |
231 | Returns the socket event type specified to the constructor. | - |
232 | | - |
233 | \sa socket() | - |
234 | */ | - |
235 | QSocketNotifier::Type QSocketNotifier::type() const | - |
236 | { | - |
237 | Q_D(const QSocketNotifier); executed (the execution status of this line is deduced): const QSocketNotifierPrivate * const d = d_func(); | - |
238 | return d->sntype; executed: return d->sntype; Execution Count:43696 | 43696 |
239 | } | - |
240 | | - |
241 | /*! | - |
242 | Returns true if the notifier is enabled; otherwise returns false. | - |
243 | | - |
244 | \sa setEnabled() | - |
245 | */ | - |
246 | bool QSocketNotifier::isEnabled() const | - |
247 | { | - |
248 | Q_D(const QSocketNotifier); executed (the execution status of this line is deduced): const QSocketNotifierPrivate * const d = d_func(); | - |
249 | return d->snenabled; executed: return d->snenabled; Execution Count:461140 | 461140 |
250 | } | - |
251 | | - |
252 | /*! | - |
253 | If \a enable is true, the notifier is enabled; otherwise the notifier | - |
254 | is disabled. | - |
255 | | - |
256 | The notifier is enabled by default, i.e. it emits the activated() | - |
257 | signal whenever a socket event corresponding to its | - |
258 | \l{type()}{type} occurs. If it is disabled, it ignores socket | - |
259 | events (the same effect as not creating the socket notifier). | - |
260 | | - |
261 | Write notifiers should normally be disabled immediately after the | - |
262 | activated() signal has been emitted | - |
263 | | - |
264 | \sa isEnabled(), activated() | - |
265 | */ | - |
266 | | - |
267 | void QSocketNotifier::setEnabled(bool enable) | - |
268 | { | - |
269 | Q_D(QSocketNotifier); executed (the execution status of this line is deduced): QSocketNotifierPrivate * const d = d_func(); | - |
270 | if (d->sockfd < 0) partially evaluated: d->sockfd < 0 no Evaluation Count:0 | yes Evaluation Count:1111499 |
| 0-1111499 |
271 | return; | 0 |
272 | if (d->snenabled == enable) // no change evaluated: d->snenabled == enable yes Evaluation Count:1041502 | yes Evaluation Count:69999 |
| 69999-1041502 |
273 | return; executed: return; Execution Count:1041502 | 1041502 |
274 | d->snenabled = enable; executed (the execution status of this line is deduced): d->snenabled = enable; | - |
275 | | - |
276 | if (!d->threadData->eventDispatcher) // perhaps application/thread is shutting down evaluated: !d->threadData->eventDispatcher yes Evaluation Count:503 | yes Evaluation Count:69502 |
| 503-69502 |
277 | return; executed: return; Execution Count:503 | 503 |
278 | if (d->snenabled) evaluated: d->snenabled yes Evaluation Count:25940 | yes Evaluation Count:43565 |
| 25940-43565 |
279 | d->threadData->eventDispatcher->registerSocketNotifier(this); executed: d->threadData->eventDispatcher->registerSocketNotifier(this); Execution Count:25939 | 25939 |
280 | else | - |
281 | d->threadData->eventDispatcher->unregisterSocketNotifier(this); executed: d->threadData->eventDispatcher->unregisterSocketNotifier(this); Execution Count:43564 | 43564 |
282 | } | - |
283 | | - |
284 | | - |
285 | /*!\reimp | - |
286 | */ | - |
287 | bool QSocketNotifier::event(QEvent *e) | - |
288 | { | - |
289 | Q_D(QSocketNotifier); executed (the execution status of this line is deduced): QSocketNotifierPrivate * const d = d_func(); | - |
290 | // Emits the activated() signal when a QEvent::SockAct or QEvent::SockClose is | - |
291 | // received. | - |
292 | if (e->type() == QEvent::ThreadChange) { evaluated: e->type() == QEvent::ThreadChange yes Evaluation Count:9 | yes Evaluation Count:2290 |
| 9-2290 |
293 | if (d->snenabled) { evaluated: d->snenabled yes Evaluation Count:7 | yes Evaluation Count:2 |
| 2-7 |
294 | QMetaObject::invokeMethod(this, "setEnabled", Qt::QueuedConnection, executed (the execution status of this line is deduced): QMetaObject::invokeMethod(this, "setEnabled", Qt::QueuedConnection, | - |
295 | Q_ARG(bool, d->snenabled)); executed (the execution status of this line is deduced): QArgument<bool >("bool", d->snenabled)); | - |
296 | setEnabled(false); executed (the execution status of this line is deduced): setEnabled(false); | - |
297 | } executed: } Execution Count:7 | 7 |
298 | } executed: } Execution Count:9 | 9 |
299 | QObject::event(e); // will activate filters executed (the execution status of this line is deduced): QObject::event(e); | - |
300 | if ((e->type() == QEvent::SockAct) || (e->type() == QEvent::SockClose)) { evaluated: (e->type() == QEvent::SockAct) yes Evaluation Count:2039 | yes Evaluation Count:261 |
partially evaluated: (e->type() == QEvent::SockClose) no Evaluation Count:0 | yes Evaluation Count:261 |
| 0-2039 |
301 | emit activated(d->sockfd, QPrivateSignal()); executed (the execution status of this line is deduced): activated(d->sockfd, QPrivateSignal()); | - |
302 | return true; executed: return true; Execution Count:2038 | 2038 |
303 | } | - |
304 | return false; executed: return false; Execution Count:261 | 261 |
305 | } | - |
306 | | - |
307 | QT_END_NAMESPACE | - |
308 | | - |
| | |