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 "qcore_unix_p.h"
41
42 #ifdef Q_OS_RTEMS
43 #include <rtems/rtems_bsdnet_internal.h>
44 #endif
45
46 QT_BEGIN_NAMESPACE
47
48 #define QT_POLL_READ_MASK (POLLIN | POLLRDNORM)
49 #define QT_POLL_WRITE_MASK (POLLOUT | POLLWRNORM | POLLWRBAND)
50 #define QT_POLL_EXCEPT_MASK (POLLPRI | POLLRDBAND)
51 #define QT_POLL_ERROR_MASK (POLLERR | POLLNVAL)
52 #define QT_POLL_EVENTS_MASK (QT_POLL_READ_MASK | QT_POLL_WRITE_MASK | QT_POLL_EXCEPT_MASK)
53
qt_poll_prepare(struct pollfd * fds,nfds_t nfds,fd_set * read_fds,fd_set * write_fds,fd_set * except_fds)54 static inline int qt_poll_prepare(struct pollfd *fds, nfds_t nfds,
55 fd_set *read_fds, fd_set *write_fds, fd_set *except_fds)
56 {
57 int max_fd = -1;
58
59 FD_ZERO(read_fds);
60 FD_ZERO(write_fds);
61 FD_ZERO(except_fds);
62
63 for (nfds_t i = 0; i < nfds; i++) {
64 if (fds[i].fd >= FD_SETSIZE) {
65 errno = EINVAL;
66 return -1;
67 }
68
69 if ((fds[i].fd < 0) || (fds[i].revents & QT_POLL_ERROR_MASK))
70 continue;
71
72 if (fds[i].events & QT_POLL_READ_MASK)
73 FD_SET(fds[i].fd, read_fds);
74
75 if (fds[i].events & QT_POLL_WRITE_MASK)
76 FD_SET(fds[i].fd, write_fds);
77
78 if (fds[i].events & QT_POLL_EXCEPT_MASK)
79 FD_SET(fds[i].fd, except_fds);
80
81 if (fds[i].events & QT_POLL_EVENTS_MASK)
82 max_fd = qMax(max_fd, fds[i].fd);
83 }
84
85 return max_fd + 1;
86 }
87
qt_poll_examine_ready_read(struct pollfd & pfd)88 static inline void qt_poll_examine_ready_read(struct pollfd &pfd)
89 {
90 int res;
91 char data;
92
93 EINTR_LOOP(res, ::recv(pfd.fd, &data, sizeof(data), MSG_PEEK));
94 const int error = (res < 0) ? errno : 0;
95
96 if (res == 0) {
97 pfd.revents |= POLLHUP;
98 } else if (res > 0 || error == ENOTSOCK || error == ENOTCONN) {
99 pfd.revents |= QT_POLL_READ_MASK & pfd.events;
100 } else {
101 switch (error) {
102 case ESHUTDOWN:
103 case ECONNRESET:
104 case ECONNABORTED:
105 case ENETRESET:
106 pfd.revents |= POLLHUP;
107 break;
108 default:
109 pfd.revents |= POLLERR;
110 break;
111 }
112 }
113 }
114
qt_poll_sweep(struct pollfd * fds,nfds_t nfds,fd_set * read_fds,fd_set * write_fds,fd_set * except_fds)115 static inline int qt_poll_sweep(struct pollfd *fds, nfds_t nfds,
116 fd_set *read_fds, fd_set *write_fds, fd_set *except_fds)
117 {
118 int result = 0;
119
120 for (nfds_t i = 0; i < nfds; i++) {
121 if (fds[i].fd < 0)
122 continue;
123
124 if (FD_ISSET(fds[i].fd, read_fds))
125 qt_poll_examine_ready_read(fds[i]);
126
127 if (FD_ISSET(fds[i].fd, write_fds))
128 fds[i].revents |= QT_POLL_WRITE_MASK & fds[i].events;
129
130 if (FD_ISSET(fds[i].fd, except_fds))
131 fds[i].revents |= QT_POLL_EXCEPT_MASK & fds[i].events;
132
133 if (fds[i].revents != 0)
134 result++;
135 }
136
137 return result;
138 }
139
qt_poll_is_bad_fd(int fd)140 static inline bool qt_poll_is_bad_fd(int fd)
141 {
142 #ifdef Q_OS_RTEMS
143 if (!rtems_bsdnet_fdToSocket(fd))
144 return true;
145 #endif
146
147 int ret;
148 EINTR_LOOP(ret, fcntl(fd, F_GETFD));
149 return (ret == -1 && errno == EBADF);
150 }
151
qt_poll_mark_bad_fds(struct pollfd * fds,const nfds_t nfds)152 static inline int qt_poll_mark_bad_fds(struct pollfd *fds, const nfds_t nfds)
153 {
154 int n_marked = 0;
155
156 for (nfds_t i = 0; i < nfds; i++) {
157 if (fds[i].fd < 0)
158 continue;
159
160 if (fds[i].revents & QT_POLL_ERROR_MASK)
161 continue;
162
163 if (qt_poll_is_bad_fd(fds[i].fd)) {
164 fds[i].revents |= POLLNVAL;
165 n_marked++;
166 }
167 }
168
169 return n_marked;
170 }
171
qt_poll(struct pollfd * fds,nfds_t nfds,const struct timespec * timeout_ts)172 int qt_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts)
173 {
174 if (!fds && nfds) {
175 errno = EFAULT;
176 return -1;
177 }
178
179 fd_set read_fds, write_fds, except_fds;
180 struct timeval tv, *ptv = 0;
181
182 if (timeout_ts) {
183 tv = timespecToTimeval(*timeout_ts);
184 ptv = &tv;
185 }
186
187 int n_bad_fds = 0;
188
189 for (nfds_t i = 0; i < nfds; i++) {
190 fds[i].revents = 0;
191
192 if (fds[i].fd < 0)
193 continue;
194
195 if (fds[i].events & QT_POLL_EVENTS_MASK)
196 continue;
197
198 if (qt_poll_is_bad_fd(fds[i].fd)) {
199 // Mark bad file descriptors that have no event flags set
200 // here, as we won't be passing them to select below and therefore
201 // need to do the check ourselves
202 fds[i].revents = POLLNVAL;
203 n_bad_fds++;
204 }
205 }
206
207 forever {
208 const int max_fd = qt_poll_prepare(fds, nfds, &read_fds, &write_fds, &except_fds);
209
210 if (max_fd < 0)
211 return max_fd;
212
213 if (n_bad_fds > 0) {
214 tv.tv_sec = 0;
215 tv.tv_usec = 0;
216 ptv = &tv;
217 }
218
219 const int ret = ::select(max_fd, &read_fds, &write_fds, &except_fds, ptv);
220
221 if (ret == 0)
222 return n_bad_fds;
223
224 if (ret > 0)
225 return qt_poll_sweep(fds, nfds, &read_fds, &write_fds, &except_fds);
226
227 if (errno != EBADF)
228 return -1;
229
230 // We have at least one bad file descriptor that we waited on, find out which and try again
231 n_bad_fds += qt_poll_mark_bad_fds(fds, nfds);
232 }
233 }
234
235 QT_END_NAMESPACE
236