summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLouai Al-Khanji <louai.al-khanji@theqtcompany.com>2015-12-02 17:22:32 -0800
committerLouai Al-Khanji <louai.al-khanji@theqtcompany.com>2015-12-05 00:47:36 +0000
commitf0a6d45cc8ca0b17838046c1c17efbc64773f2b5 (patch)
tree5ce13632dc05400b4c61ff817b01322111abde24 /src
parentc456fb366a92cd08f6d2bf95b6974fea82340003 (diff)
qt_poll: split out into separate file and sanitize build
The qt_poll function calls recv to query whether fds marked by select as readable should be marked POLLIN or POLLHUP in the pollfd structure. On many platforms such as QNX this requires extra link-time libraries which were not previously required by QtCore. While the qt_poll function is intended as a fallback mechanism only for those platforms which do not implement poll natively, the function was compiled unconditionally whenever QT_BUILD_INTERNAL was defined, e.g. in developer builds. Additionally the function was included on those systems that define poll in system headers so that configure determines build-time availability, but do not define _POSIX_POLL > 0 or indicate POSIX:2008 compliance via either the _POSIX_VERSION or _XOPEN_VERSION macros. On those systems a sysconf query for _SC_POLL was performed to determine at runtime whether to call the system poll or qt_poll. Both of these cases are in fact counterproductive. In the first case the sole consumer of the function is a single manual unit test. In the second, to my knowledge no platform requires the runtime fallback. Despite that, we were forcing an extra dylib in both cases. Both cases are fixed by 1) moving the implementation into its own file for the unit test to include and 2) dropping the dynamic fallback if configure determines availability of poll at compile-time. This also reverts commit 13777097118c496391d4b9656b95097ac25e4a40, which added -lsocket for QtCore on QNX. Change-Id: I2dd10695c5d4cac81b68d2c2558797f3cdabc153 Reviewed-by: James McDonnell <jmcdonnell@qnx.com> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src')
-rw-r--r--src/corelib/kernel/kernel.pri2
-rw-r--r--src/corelib/kernel/qcore_unix.cpp220
-rw-r--r--src/corelib/kernel/qcore_unix_p.h30
-rw-r--r--src/corelib/kernel/qpoll.cpp220
-rw-r--r--src/corelib/kernel/qpoll_p.h79
5 files changed, 317 insertions, 234 deletions
diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri
index aabe076062..c51305b3d5 100644
--- a/src/corelib/kernel/kernel.pri
+++ b/src/corelib/kernel/kernel.pri
@@ -141,8 +141,10 @@ unix|integrity {
kernel/qcore_unix_p.h \
kernel/qcrashhandler_p.h \
kernel/qeventdispatcher_unix_p.h \
+ kernel/qpoll_p.h \
kernel/qtimerinfo_unix_p.h
+ contains(QT_CONFIG, poll_select): SOURCES += kernel/qpoll.cpp
contains(QT_CONFIG, poll_poll): DEFINES += QT_HAVE_POLL
contains(QT_CONFIG, poll_ppoll): DEFINES += QT_HAVE_POLL QT_HAVE_PPOLL
contains(QT_CONFIG, poll_pollts): DEFINES += QT_HAVE_POLL QT_HAVE_POLLTS
diff --git a/src/corelib/kernel/qcore_unix.cpp b/src/corelib/kernel/qcore_unix.cpp
index bb75823bff..97c0efc36f 100644
--- a/src/corelib/kernel/qcore_unix.cpp
+++ b/src/corelib/kernel/qcore_unix.cpp
@@ -57,28 +57,6 @@ QT_BEGIN_NAMESPACE
# define QT_HAVE_PPOLL
#endif
-#ifndef _POSIX_POLL
-# if defined(QT_HAVE_PPOLL) || _POSIX_VERSION >= 200809L || _XOPEN_VERSION >= 700
-# define _POSIX_POLL 1
-# elif defined(QT_HAVE_POLL)
-# define _POSIX_POLL 0
-# else
-# define _POSIX_POLL -1
-# endif
-#endif
-
-#if defined(Q_OS_QNX) || _POSIX_POLL <= 0 || defined(QT_BUILD_INTERNAL)
-static inline struct timeval timespecToTimeval(const struct timespec &ts)
-{
- struct timeval tv;
-
- tv.tv_sec = ts.tv_sec;
- tv.tv_usec = ts.tv_nsec / 1000;
-
- return tv;
-}
-#endif
-
static inline bool time_update(struct timespec *tv, const struct timespec &start,
const struct timespec &timeout)
{
@@ -142,193 +120,7 @@ int qt_select_msecs(int nfds, fd_set *fdread, fd_set *fdwrite, int timeout)
return qt_safe_select(nfds, fdread, fdwrite, 0, &tv);
}
-#if _POSIX_POLL <= 0 || defined(QT_BUILD_INTERNAL)
-
-#define QT_POLL_READ_MASK (POLLIN | POLLRDNORM)
-#define QT_POLL_WRITE_MASK (POLLOUT | POLLWRNORM | POLLWRBAND)
-#define QT_POLL_EXCEPT_MASK (POLLPRI | POLLRDBAND)
-#define QT_POLL_ERROR_MASK (POLLERR | POLLNVAL)
-#define QT_POLL_EVENTS_MASK (QT_POLL_READ_MASK | QT_POLL_WRITE_MASK | QT_POLL_EXCEPT_MASK)
-
-static inline int qt_poll_prepare(struct pollfd *fds, nfds_t nfds,
- fd_set *read_fds, fd_set *write_fds, fd_set *except_fds)
-{
- int max_fd = -1;
-
- FD_ZERO(read_fds);
- FD_ZERO(write_fds);
- FD_ZERO(except_fds);
-
- for (nfds_t i = 0; i < nfds; i++) {
- if (fds[i].fd >= FD_SETSIZE) {
- errno = EINVAL;
- return -1;
- }
-
- if ((fds[i].fd < 0) || (fds[i].revents & QT_POLL_ERROR_MASK))
- continue;
-
- if (fds[i].events & QT_POLL_READ_MASK)
- FD_SET(fds[i].fd, read_fds);
-
- if (fds[i].events & QT_POLL_WRITE_MASK)
- FD_SET(fds[i].fd, write_fds);
-
- if (fds[i].events & QT_POLL_EXCEPT_MASK)
- FD_SET(fds[i].fd, except_fds);
-
- if (fds[i].events & QT_POLL_EVENTS_MASK)
- max_fd = qMax(max_fd, fds[i].fd);
- }
-
- return max_fd + 1;
-}
-
-static inline void qt_poll_examine_ready_read(struct pollfd &pfd)
-{
- int res;
- char data;
-
- EINTR_LOOP(res, ::recv(pfd.fd, &data, sizeof(data), MSG_PEEK));
- const int error = (res < 0) ? errno : 0;
-
- if (res == 0) {
- pfd.revents |= POLLHUP;
- } else if (res > 0 || error == ENOTSOCK || error == ENOTCONN) {
- pfd.revents |= QT_POLL_READ_MASK & pfd.events;
- } else {
- switch (error) {
- case ESHUTDOWN:
- case ECONNRESET:
- case ECONNABORTED:
- case ENETRESET:
- pfd.revents |= POLLHUP;
- break;
- default:
- pfd.revents |= POLLERR;
- break;
- }
- }
-}
-
-static inline int qt_poll_sweep(struct pollfd *fds, nfds_t nfds,
- fd_set *read_fds, fd_set *write_fds, fd_set *except_fds)
-{
- int result = 0;
-
- for (nfds_t i = 0; i < nfds; i++) {
- if (fds[i].fd < 0)
- continue;
-
- if (FD_ISSET(fds[i].fd, read_fds))
- qt_poll_examine_ready_read(fds[i]);
-
- if (FD_ISSET(fds[i].fd, write_fds))
- fds[i].revents |= QT_POLL_WRITE_MASK & fds[i].events;
-
- if (FD_ISSET(fds[i].fd, except_fds))
- fds[i].revents |= QT_POLL_EXCEPT_MASK & fds[i].events;
-
- if (fds[i].revents != 0)
- result++;
- }
-
- return result;
-}
-
-static inline bool qt_poll_is_bad_fd(int fd)
-{
- int ret;
- EINTR_LOOP(ret, fcntl(fd, F_GETFD));
- return (ret == -1 && errno == EBADF);
-}
-
-static inline int qt_poll_mark_bad_fds(struct pollfd *fds, const nfds_t nfds)
-{
- int n_marked = 0;
-
- for (nfds_t i = 0; i < nfds; i++) {
- if (fds[i].fd < 0)
- continue;
-
- if (fds[i].revents & QT_POLL_ERROR_MASK)
- continue;
-
- if (qt_poll_is_bad_fd(fds[i].fd)) {
- fds[i].revents |= POLLNVAL;
- n_marked++;
- }
- }
-
- return n_marked;
-}
-
-Q_AUTOTEST_EXPORT int qt_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts)
-{
- if (!fds && nfds) {
- errno = EFAULT;
- return -1;
- }
-
- fd_set read_fds, write_fds, except_fds;
- struct timeval tv, *ptv = 0;
-
- if (timeout_ts) {
- tv = timespecToTimeval(*timeout_ts);
- ptv = &tv;
- }
-
- int n_bad_fds = 0;
-
- for (nfds_t i = 0; i < nfds; i++) {
- fds[i].revents = 0;
-
- if (fds[i].fd < 0)
- continue;
-
- if (fds[i].events & QT_POLL_EVENTS_MASK)
- continue;
-
- if (qt_poll_is_bad_fd(fds[i].fd)) {
- // Mark bad file descriptors that have no event flags set
- // here, as we won't be passing them to select below and therefore
- // need to do the check ourselves
- fds[i].revents = POLLNVAL;
- n_bad_fds++;
- }
- }
-
- forever {
- const int max_fd = qt_poll_prepare(fds, nfds, &read_fds, &write_fds, &except_fds);
-
- if (max_fd < 0)
- return max_fd;
-
- if (n_bad_fds > 0) {
- tv.tv_sec = 0;
- tv.tv_usec = 0;
- ptv = &tv;
- }
-
- const int ret = ::select(max_fd, &read_fds, &write_fds, &except_fds, ptv);
-
- if (ret == 0)
- return n_bad_fds;
-
- if (ret > 0)
- return qt_poll_sweep(fds, nfds, &read_fds, &write_fds, &except_fds);
-
- if (errno != EBADF)
- return -1;
-
- // We have at least one bad file descriptor that we waited on, find out which and try again
- n_bad_fds += qt_poll_mark_bad_fds(fds, nfds);
- }
-}
-
-#endif // _POSIX_POLL <= 0 || defined(QT_BUILD_INTERNAL)
-
-#if !defined(QT_HAVE_PPOLL) && ((_POSIX_POLL > 0) || defined(_SC_POLL))
+#if !defined(QT_HAVE_PPOLL) && defined(QT_HAVE_POLL)
static inline int timespecToMillisecs(const struct timespec *ts)
{
return (ts == NULL) ? -1 :
@@ -336,18 +128,16 @@ static inline int timespecToMillisecs(const struct timespec *ts)
}
#endif
+// defined in qpoll.cpp
+int qt_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts);
+
static inline int qt_ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts)
{
#if defined(QT_HAVE_PPOLL)
return ::ppoll(fds, nfds, timeout_ts, Q_NULLPTR);
-#elif _POSIX_POLL > 0
+#elif defined(QT_HAVE_POLL)
return ::poll(fds, nfds, timespecToMillisecs(timeout_ts));
#else
-# if defined(_SC_POLL)
- static const bool have_poll = (sysconf(_SC_POLL) > 0);
- if (have_poll)
- return ::poll(fds, nfds, timespecToMillisecs(timeout_ts));
-# endif
return qt_poll(fds, nfds, timeout_ts);
#endif
}
diff --git a/src/corelib/kernel/qcore_unix_p.h b/src/corelib/kernel/qcore_unix_p.h
index d5434888d0..fcc65589a0 100644
--- a/src/corelib/kernel/qcore_unix_p.h
+++ b/src/corelib/kernel/qcore_unix_p.h
@@ -66,26 +66,10 @@
# include <ioLib.h>
#endif
-#ifndef QT_NO_NATIVE_POLL
-# include <poll.h>
+#ifdef QT_NO_NATIVE_POLL
+# include "qpoll_p.h"
#else
-struct pollfd {
- int fd;
- short events, revents;
-};
-
-typedef unsigned long int nfds_t;
-
-# define POLLIN 0x001
-# define POLLPRI 0x002
-# define POLLOUT 0x004
-# define POLLERR 0x008
-# define POLLHUP 0x010
-# define POLLNVAL 0x020
-# define POLLRDNORM 0x040
-# define POLLRDBAND 0x080
-# define POLLWRNORM 0x100
-# define POLLWRBAND 0x200
+# include <poll.h>
#endif
struct sockaddr;
@@ -143,6 +127,14 @@ inline timespec operator*(const timespec &t1, int mul)
tmp.tv_nsec = t1.tv_nsec * mul;
return normalizedTimespec(tmp);
}
+inline timeval timespecToTimeval(const timespec &ts)
+{
+ timeval tv;
+ tv.tv_sec = ts.tv_sec;
+ tv.tv_usec = ts.tv_nsec / 1000;
+ return tv;
+}
+
inline void qt_ignore_sigpipe()
{
diff --git a/src/corelib/kernel/qpoll.cpp b/src/corelib/kernel/qpoll.cpp
new file mode 100644
index 0000000000..b152518c00
--- /dev/null
+++ b/src/corelib/kernel/qpoll.cpp
@@ -0,0 +1,220 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcore_unix_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#define QT_POLL_READ_MASK (POLLIN | POLLRDNORM)
+#define QT_POLL_WRITE_MASK (POLLOUT | POLLWRNORM | POLLWRBAND)
+#define QT_POLL_EXCEPT_MASK (POLLPRI | POLLRDBAND)
+#define QT_POLL_ERROR_MASK (POLLERR | POLLNVAL)
+#define QT_POLL_EVENTS_MASK (QT_POLL_READ_MASK | QT_POLL_WRITE_MASK | QT_POLL_EXCEPT_MASK)
+
+static inline int qt_poll_prepare(struct pollfd *fds, nfds_t nfds,
+ fd_set *read_fds, fd_set *write_fds, fd_set *except_fds)
+{
+ int max_fd = -1;
+
+ FD_ZERO(read_fds);
+ FD_ZERO(write_fds);
+ FD_ZERO(except_fds);
+
+ for (nfds_t i = 0; i < nfds; i++) {
+ if (fds[i].fd >= FD_SETSIZE) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if ((fds[i].fd < 0) || (fds[i].revents & QT_POLL_ERROR_MASK))
+ continue;
+
+ if (fds[i].events & QT_POLL_READ_MASK)
+ FD_SET(fds[i].fd, read_fds);
+
+ if (fds[i].events & QT_POLL_WRITE_MASK)
+ FD_SET(fds[i].fd, write_fds);
+
+ if (fds[i].events & QT_POLL_EXCEPT_MASK)
+ FD_SET(fds[i].fd, except_fds);
+
+ if (fds[i].events & QT_POLL_EVENTS_MASK)
+ max_fd = qMax(max_fd, fds[i].fd);
+ }
+
+ return max_fd + 1;
+}
+
+static inline void qt_poll_examine_ready_read(struct pollfd &pfd)
+{
+ int res;
+ char data;
+
+ EINTR_LOOP(res, ::recv(pfd.fd, &data, sizeof(data), MSG_PEEK));
+ const int error = (res < 0) ? errno : 0;
+
+ if (res == 0) {
+ pfd.revents |= POLLHUP;
+ } else if (res > 0 || error == ENOTSOCK || error == ENOTCONN) {
+ pfd.revents |= QT_POLL_READ_MASK & pfd.events;
+ } else {
+ switch (error) {
+ case ESHUTDOWN:
+ case ECONNRESET:
+ case ECONNABORTED:
+ case ENETRESET:
+ pfd.revents |= POLLHUP;
+ break;
+ default:
+ pfd.revents |= POLLERR;
+ break;
+ }
+ }
+}
+
+static inline int qt_poll_sweep(struct pollfd *fds, nfds_t nfds,
+ fd_set *read_fds, fd_set *write_fds, fd_set *except_fds)
+{
+ int result = 0;
+
+ for (nfds_t i = 0; i < nfds; i++) {
+ if (fds[i].fd < 0)
+ continue;
+
+ if (FD_ISSET(fds[i].fd, read_fds))
+ qt_poll_examine_ready_read(fds[i]);
+
+ if (FD_ISSET(fds[i].fd, write_fds))
+ fds[i].revents |= QT_POLL_WRITE_MASK & fds[i].events;
+
+ if (FD_ISSET(fds[i].fd, except_fds))
+ fds[i].revents |= QT_POLL_EXCEPT_MASK & fds[i].events;
+
+ if (fds[i].revents != 0)
+ result++;
+ }
+
+ return result;
+}
+
+static inline bool qt_poll_is_bad_fd(int fd)
+{
+ int ret;
+ EINTR_LOOP(ret, fcntl(fd, F_GETFD));
+ return (ret == -1 && errno == EBADF);
+}
+
+static inline int qt_poll_mark_bad_fds(struct pollfd *fds, const nfds_t nfds)
+{
+ int n_marked = 0;
+
+ for (nfds_t i = 0; i < nfds; i++) {
+ if (fds[i].fd < 0)
+ continue;
+
+ if (fds[i].revents & QT_POLL_ERROR_MASK)
+ continue;
+
+ if (qt_poll_is_bad_fd(fds[i].fd)) {
+ fds[i].revents |= POLLNVAL;
+ n_marked++;
+ }
+ }
+
+ return n_marked;
+}
+
+int qt_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts)
+{
+ if (!fds && nfds) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ fd_set read_fds, write_fds, except_fds;
+ struct timeval tv, *ptv = 0;
+
+ if (timeout_ts) {
+ tv = timespecToTimeval(*timeout_ts);
+ ptv = &tv;
+ }
+
+ int n_bad_fds = 0;
+
+ for (nfds_t i = 0; i < nfds; i++) {
+ fds[i].revents = 0;
+
+ if (fds[i].fd < 0)
+ continue;
+
+ if (fds[i].events & QT_POLL_EVENTS_MASK)
+ continue;
+
+ if (qt_poll_is_bad_fd(fds[i].fd)) {
+ // Mark bad file descriptors that have no event flags set
+ // here, as we won't be passing them to select below and therefore
+ // need to do the check ourselves
+ fds[i].revents = POLLNVAL;
+ n_bad_fds++;
+ }
+ }
+
+ forever {
+ const int max_fd = qt_poll_prepare(fds, nfds, &read_fds, &write_fds, &except_fds);
+
+ if (max_fd < 0)
+ return max_fd;
+
+ if (n_bad_fds > 0) {
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ ptv = &tv;
+ }
+
+ const int ret = ::select(max_fd, &read_fds, &write_fds, &except_fds, ptv);
+
+ if (ret == 0)
+ return n_bad_fds;
+
+ if (ret > 0)
+ return qt_poll_sweep(fds, nfds, &read_fds, &write_fds, &except_fds);
+
+ if (errno != EBADF)
+ return -1;
+
+ // We have at least one bad file descriptor that we waited on, find out which and try again
+ n_bad_fds += qt_poll_mark_bad_fds(fds, nfds);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qpoll_p.h b/src/corelib/kernel/qpoll_p.h
new file mode 100644
index 0000000000..497058ad6b
--- /dev/null
+++ b/src/corelib/kernel/qpoll_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPOLL_P_H
+#define QPOLL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of Qt code on Unix. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifdef QT_NO_NATIVE_POLL
+
+#include <unistd.h>
+#include <time.h>
+
+struct pollfd {
+ int fd;
+ short events, revents;
+};
+
+typedef unsigned long int nfds_t;
+
+#define POLLIN 0x001
+#define POLLPRI 0x002
+#define POLLOUT 0x004
+#define POLLERR 0x008
+#define POLLHUP 0x010
+#define POLLNVAL 0x020
+#define POLLRDNORM 0x040
+#define POLLRDBAND 0x080
+#define POLLWRNORM 0x100
+#define POLLWRBAND 0x200
+
+#endif // QT_NO_NATIVE_POLL
+
+QT_END_NAMESPACE
+
+#endif // QPOLL_P_H