Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qpoll.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include "qcore_unix_p.h"
6
7#ifdef Q_OS_RTEMS
8#include <rtems/rtems_bsdnet_internal.h>
9#endif
10
12
13#define QT_POLL_READ_MASK (POLLIN | POLLRDNORM)
14#define QT_POLL_WRITE_MASK (POLLOUT | POLLWRNORM | POLLWRBAND)
15#define QT_POLL_EXCEPT_MASK (POLLPRI | POLLRDBAND)
16#define QT_POLL_ERROR_MASK (POLLERR | POLLNVAL)
18
19static inline int qt_poll_prepare(struct pollfd *fds, nfds_t nfds,
20 fd_set *read_fds, fd_set *write_fds, fd_set *except_fds)
21{
22 int max_fd = -1;
23
24 FD_ZERO(read_fds);
25 FD_ZERO(write_fds);
26 FD_ZERO(except_fds);
27
28 for (nfds_t i = 0; i < nfds; i++) {
29 if (fds[i].fd >= FD_SETSIZE) {
30 errno = EINVAL;
31 return -1;
32 }
33
34 if ((fds[i].fd < 0) || (fds[i].revents & QT_POLL_ERROR_MASK))
35 continue;
36
37 if (fds[i].events & QT_POLL_READ_MASK)
38 FD_SET(fds[i].fd, read_fds);
39
40 if (fds[i].events & QT_POLL_WRITE_MASK)
41 FD_SET(fds[i].fd, write_fds);
42
43 if (fds[i].events & QT_POLL_EXCEPT_MASK)
44 FD_SET(fds[i].fd, except_fds);
45
46 if (fds[i].events & QT_POLL_EVENTS_MASK)
47 max_fd = qMax(max_fd, fds[i].fd);
48 }
49
50 return max_fd + 1;
51}
52
53static inline void qt_poll_examine_ready_read(struct pollfd &pfd)
54{
55 int res;
56 char data;
57
58 QT_EINTR_LOOP(res, ::recv(pfd.fd, &data, sizeof(data), MSG_PEEK));
59 const int error = (res < 0) ? errno : 0;
60
61 if (res == 0) {
62 pfd.revents |= POLLHUP;
63 } else if (res > 0 || error == ENOTSOCK || error == ENOTCONN) {
64 pfd.revents |= QT_POLL_READ_MASK & pfd.events;
65 } else {
66 switch (error) {
67 case ESHUTDOWN:
68 case ECONNRESET:
69 case ECONNABORTED:
70 case ENETRESET:
71 pfd.revents |= POLLHUP;
72 break;
73 default:
74 pfd.revents |= POLLERR;
75 break;
76 }
77 }
78}
79
80static inline int qt_poll_sweep(struct pollfd *fds, nfds_t nfds,
81 fd_set *read_fds, fd_set *write_fds, fd_set *except_fds)
82{
83 int result = 0;
84
85 for (nfds_t i = 0; i < nfds; i++) {
86 if (fds[i].fd < 0)
87 continue;
88
89 if (FD_ISSET(fds[i].fd, read_fds))
91
92 if (FD_ISSET(fds[i].fd, write_fds))
93 fds[i].revents |= QT_POLL_WRITE_MASK & fds[i].events;
94
95 if (FD_ISSET(fds[i].fd, except_fds))
96 fds[i].revents |= QT_POLL_EXCEPT_MASK & fds[i].events;
97
98 if (fds[i].revents != 0)
99 result++;
100 }
101
102 return result;
103}
104
105static inline bool qt_poll_is_bad_fd(int fd)
106{
107#ifdef Q_OS_RTEMS
108 if (!rtems_bsdnet_fdToSocket(fd))
109 return true;
110#endif
111
112 int ret;
113 QT_EINTR_LOOP(ret, fcntl(fd, F_GETFD));
114 return (ret == -1 && errno == EBADF);
115}
116
117static inline int qt_poll_mark_bad_fds(struct pollfd *fds, const nfds_t nfds)
118{
119 int n_marked = 0;
120
121 for (nfds_t i = 0; i < nfds; i++) {
122 if (fds[i].fd < 0)
123 continue;
124
125 if (fds[i].revents & QT_POLL_ERROR_MASK)
126 continue;
127
128 if (qt_poll_is_bad_fd(fds[i].fd)) {
129 fds[i].revents |= POLLNVAL;
130 n_marked++;
131 }
132 }
133
134 return n_marked;
135}
136
137int qt_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts)
138{
139 if (!fds && nfds) {
140 errno = EFAULT;
141 return -1;
142 }
143
144 fd_set read_fds, write_fds, except_fds;
145 struct timeval tv, *ptv = nullptr;
146
147 if (timeout_ts) {
148 tv = timespecToTimeval(*timeout_ts);
149 ptv = &tv;
150 }
151
152 int n_bad_fds = 0;
153
154 for (nfds_t i = 0; i < nfds; i++) {
155 fds[i].revents = 0;
156
157 if (fds[i].fd < 0)
158 continue;
159
160 if (fds[i].fd > FD_SETSIZE) {
161 errno = EINVAL;
162 return -1;
163 }
164
165 if (fds[i].events & QT_POLL_EVENTS_MASK)
166 continue;
167
168 if (qt_poll_is_bad_fd(fds[i].fd)) {
169 // Mark bad file descriptors that have no event flags set
170 // here, as we won't be passing them to select below and therefore
171 // need to do the check ourselves
172 fds[i].revents = POLLNVAL;
173 n_bad_fds++;
174 }
175 }
176
177 forever {
178 const int max_fd = qt_poll_prepare(fds, nfds, &read_fds, &write_fds, &except_fds);
179
180 if (max_fd < 0)
181 return max_fd;
182
183 if (n_bad_fds > 0) {
184 tv.tv_sec = 0;
185 tv.tv_usec = 0;
186 ptv = &tv;
187 }
188
189 const int ret = ::select(max_fd, &read_fds, &write_fds, &except_fds, ptv);
190
191 if (ret == 0)
192 return n_bad_fds;
193
194 if (ret > 0)
195 return qt_poll_sweep(fds, nfds, &read_fds, &write_fds, &except_fds);
196
197 if (errno != EBADF)
198 return -1;
199
200 // We have at least one bad file descriptor that we waited on, find out which and try again
201 n_bad_fds += qt_poll_mark_bad_fds(fds, nfds);
202 }
203}
204
205QT_END_NAMESPACE
Combined button and popup list for selecting options.
int qt_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts)
Definition qpoll.cpp:137
#define QT_EINTR_LOOP(var, cmd)
timeval timespecToTimeval(timespec ts)
static int qt_poll_prepare(struct pollfd *fds, nfds_t nfds, fd_set *read_fds, fd_set *write_fds, fd_set *except_fds)
Definition qpoll.cpp:19
static void qt_poll_examine_ready_read(struct pollfd &pfd)
Definition qpoll.cpp:53
#define QT_POLL_READ_MASK
Definition qpoll.cpp:13
#define QT_POLL_ERROR_MASK
Definition qpoll.cpp:16
#define QT_POLL_EVENTS_MASK
Definition qpoll.cpp:17
#define QT_POLL_EXCEPT_MASK
Definition qpoll.cpp:15
static int qt_poll_mark_bad_fds(struct pollfd *fds, const nfds_t nfds)
Definition qpoll.cpp:117
static int qt_poll_sweep(struct pollfd *fds, nfds_t nfds, fd_set *read_fds, fd_set *write_fds, fd_set *except_fds)
Definition qpoll.cpp:80
static bool qt_poll_is_bad_fd(int fd)
Definition qpoll.cpp:105
#define QT_POLL_WRITE_MASK
Definition qpoll.cpp:14