diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/kernel/kernel.pri | 2 | ||||
-rw-r--r-- | src/corelib/kernel/qcore_unix.cpp | 220 | ||||
-rw-r--r-- | src/corelib/kernel/qcore_unix_p.h | 30 | ||||
-rw-r--r-- | src/corelib/kernel/qpoll.cpp | 220 | ||||
-rw-r--r-- | src/corelib/kernel/qpoll_p.h | 79 |
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 |