Blob Blame History Raw
diff --git a/config.tests/unix/poll/poll.cpp b/config.tests/unix/poll/poll.cpp
new file mode 100644
index 0000000..06ae038
--- /dev/null
+++ b/config.tests/unix/poll/poll.cpp
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the config.tests 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 <poll.h>
+
+int main()
+{
+    struct pollfd pfd;
+
+    pfd.fd = -1;
+    pfd.events = 0;
+    pfd.revents = 0;
+
+    return ::poll(&pfd, 1, 0);
+}
diff --git a/config.tests/unix/poll/poll.pro b/config.tests/unix/poll/poll.pro
new file mode 100644
index 0000000..70121b4
--- /dev/null
+++ b/config.tests/unix/poll/poll.pro
@@ -0,0 +1,2 @@
+SOURCES = poll.cpp
+CONFIG -= qt
diff --git a/config.tests/unix/pollts/poll/poll.cpp b/config.tests/unix/pollts/poll/poll.cpp
new file mode 100644
index 0000000..06ae038
--- /dev/null
+++ b/config.tests/unix/pollts/poll/poll.cpp
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the config.tests 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 <poll.h>
+
+int main()
+{
+    struct pollfd pfd;
+
+    pfd.fd = -1;
+    pfd.events = 0;
+    pfd.revents = 0;
+
+    return ::poll(&pfd, 1, 0);
+}
diff --git a/config.tests/unix/pollts/poll/poll.pro b/config.tests/unix/pollts/poll/poll.pro
new file mode 100644
index 0000000..70121b4
--- /dev/null
+++ b/config.tests/unix/pollts/poll/poll.pro
@@ -0,0 +1,2 @@
+SOURCES = poll.cpp
+CONFIG -= qt
diff --git a/config.tests/unix/pollts/pollts.cpp b/config.tests/unix/pollts/pollts.cpp
new file mode 100644
index 0000000..c2d1940
--- /dev/null
+++ b/config.tests/unix/pollts/pollts.cpp
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the config.tests 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 <poll.h>
+#include <signal.h>
+#include <time.h>
+
+int main()
+{
+    struct pollfd pfd;
+    struct timespec ts;
+
+    pfd.fd = -1;
+    pfd.events = 0;
+    pfd.revents = 0;
+
+    ts.tv_sec = 0;
+    ts.tv_nsec = 0;
+
+    return ::pollts(&pfd, 1, &ts, nullptr);
+}
diff --git a/config.tests/unix/pollts/pollts/poll/poll.cpp b/config.tests/unix/pollts/pollts/poll/poll.cpp
new file mode 100644
index 0000000..06ae038
--- /dev/null
+++ b/config.tests/unix/pollts/pollts/poll/poll.cpp
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the config.tests 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 <poll.h>
+
+int main()
+{
+    struct pollfd pfd;
+
+    pfd.fd = -1;
+    pfd.events = 0;
+    pfd.revents = 0;
+
+    return ::poll(&pfd, 1, 0);
+}
diff --git a/config.tests/unix/pollts/pollts/poll/poll.pro b/config.tests/unix/pollts/pollts/poll/poll.pro
new file mode 100644
index 0000000..70121b4
--- /dev/null
+++ b/config.tests/unix/pollts/pollts/poll/poll.pro
@@ -0,0 +1,2 @@
+SOURCES = poll.cpp
+CONFIG -= qt
diff --git a/config.tests/unix/pollts/pollts/pollts.cpp b/config.tests/unix/pollts/pollts/pollts.cpp
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/config.tests/unix/pollts/pollts/pollts.cpp
@@ -0,0 +1 @@
+
diff --git a/config.tests/unix/pollts/pollts/pollts.pro b/config.tests/unix/pollts/pollts/pollts.pro
new file mode 100644
index 0000000..5109dc3
--- /dev/null
+++ b/config.tests/unix/pollts/pollts/pollts.pro
@@ -0,0 +1,2 @@
+SOURCES = pollts.cpp
+CONFIG -= qt
diff --git a/config.tests/unix/ppoll/ppoll.cpp b/config.tests/unix/ppoll/ppoll.cpp
new file mode 100644
index 0000000..5b0cc4d
--- /dev/null
+++ b/config.tests/unix/ppoll/ppoll.cpp
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the config.tests 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 <signal.h>
+#include <poll.h>
+
+int main()
+{
+    struct pollfd pfd;
+    struct timespec ts;
+
+    pfd.fd = -1;
+    pfd.events = 0;
+    pfd.revents = 0;
+
+    ts.tv_sec = 0;
+    ts.tv_nsec = 0;
+
+    return ::ppoll(&pfd, 1, &ts, nullptr);
+}
+
diff --git a/config.tests/unix/ppoll/ppoll.pro b/config.tests/unix/ppoll/ppoll.pro
new file mode 100644
index 0000000..d08a8a0
--- /dev/null
+++ b/config.tests/unix/ppoll/ppoll.pro
@@ -0,0 +1,2 @@
+SOURCES = ppoll.cpp
+CONFIG -= qt
diff --git a/configure b/configure
index 7651e29..9be4179 100755
--- a/configure
+++ b/configure
@@ -729,6 +729,7 @@ CFG_GETIFADDRS=auto
 CFG_INOTIFY=auto
 CFG_EVENTFD=auto
 CFG_CLOEXEC=no
+CFG_POLL=auto
 CFG_RPATH=yes
 CFG_FRAMEWORK=auto
 CFG_USE_GOLD_LINKER=auto
@@ -6043,6 +6044,16 @@ if compileTest unix/cloexec "cloexec"; then
     CFG_CLOEXEC=yes
 fi

+if compileTest unix/ppoll "ppoll"; then
+    CFG_POLL="ppoll"
+elif compileTest unix/pollts "pollts"; then
+    CFG_POLL="pollts"
+elif compileTest unix/poll "poll"; then
+    CFG_POLL="poll"
+else
+    CFG_POLL="select"
+fi
+
 if [ "$XPLATFORM_MAC" = "yes" ] && [ "$CFG_SECURETRANSPORT" != "no" ] && ([ "$CFG_OPENSSL" = "no" ] || [ "$CFG_OPENSSL" = "auto" ]); then
     CFG_SECURETRANSPORT=yes
     CFG_OPENSSL=no
@@ -6350,6 +6361,10 @@ fi
 if [ "$CFG_CLOEXEC" = "yes" ]; then
     QT_CONFIG="$QT_CONFIG threadsafe-cloexec"
 fi
+if [ "$CFG_POLL" = "select" ]; then
+    QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_NATIVE_POLL"
+fi
+QT_CONFIG="$QT_CONFIG poll_$CFG_POLL"
 if [ "$CFG_LIBJPEG" = "no" ]; then
     CFG_JPEG="no"
 elif [ "$CFG_LIBJPEG" = "system" ]; then
diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp
index 8eb5ac9..74a0c41 100644
--- a/src/corelib/io/qprocess_unix.cpp
+++ b/src/corelib/io/qprocess_unix.cpp
@@ -115,11 +115,52 @@ QT_BEGIN_NAMESPACE
 // so we will use 512
 static const int errorBufferMax = 512;

-static inline void add_fd(int &nfds, int fd, fd_set *fdset)
+namespace {
+struct QProcessPoller
 {
-    FD_SET(fd, fdset);
-    if ((fd) > nfds)
-        nfds = fd;
+    QProcessPoller(const QProcessPrivate &proc);
+
+    int poll(int timeout);
+
+    pollfd &stdinPipe() { return pfds[0]; }
+    pollfd &stdoutPipe() { return pfds[1]; }
+    pollfd &stderrPipe() { return pfds[2]; }
+    pollfd &forkfd() { return pfds[3]; }
+    pollfd &childStartedPipe() { return pfds[4]; }
+
+    enum { n_pfds = 5 };
+    pollfd pfds[n_pfds];
+};
+
+QProcessPoller::QProcessPoller(const QProcessPrivate &proc)
+{
+    for (int i = 0; i < n_pfds; i++)
+        pfds[i] = qt_make_pollfd(-1, POLLIN);
+
+    stdoutPipe().fd = proc.stdoutChannel.pipe[0];
+    stderrPipe().fd = proc.stderrChannel.pipe[0];
+
+    if (!proc.stdinChannel.buffer.isEmpty()) {
+        stdinPipe().fd = proc.stdinChannel.pipe[1];
+        stdinPipe().events = POLLOUT;
+    }
+
+    forkfd().fd = proc.forkfd;
+
+    if (proc.processState == QProcess::Starting)
+        childStartedPipe().fd = proc.childStartedPipe[0];
+}
+
+int QProcessPoller::poll(int timeout)
+{
+    const nfds_t nfds = (childStartedPipe().fd == -1) ? 4 : 5;
+    return qt_poll_msecs(pfds, nfds, timeout);
+}
+} // anonymous namespace
+
+static bool qt_pollfd_check(const pollfd &pfd, short revents)
+{
+    return pfd.fd >= 0 && (pfd.revents & (revents | POLLHUP | POLLERR | POLLNVAL)) != 0;
 }

 static int qt_create_pipe(int *pipe)
@@ -812,10 +853,9 @@ bool QProcessPrivate::waitForStarted(int msecs)
            childStartedPipe[0]);
 #endif

-    fd_set fds;
-    FD_ZERO(&fds);
-    FD_SET(childStartedPipe[0], &fds);
-    if (qt_select_msecs(childStartedPipe[0] + 1, &fds, 0, msecs) == 0) {
+    pollfd pfd = qt_make_pollfd(childStartedPipe[0], POLLIN);
+
+    if (qt_poll_msecs(&pfd, 1, msecs) == 0) {
         setError(QProcess::Timedout);
 #if defined (QPROCESS_DEBUG)
         qDebug("QProcessPrivate::waitForStarted(%d) == false (timed out)", msecs);
@@ -855,31 +895,13 @@ bool QProcessPrivate::waitForReadyRead(int msecs)
 #endif

     forever {
-        fd_set fdread;
-        fd_set fdwrite;
-
-        FD_ZERO(&fdread);
-        FD_ZERO(&fdwrite);
-
-        int nfds = forkfd;
-        FD_SET(forkfd, &fdread);
-
-        if (processState == QProcess::Starting)
-            add_fd(nfds, childStartedPipe[0], &fdread);
-
-        if (stdoutChannel.pipe[0] != -1)
-            add_fd(nfds, stdoutChannel.pipe[0], &fdread);
-        if (stderrChannel.pipe[0] != -1)
-            add_fd(nfds, stderrChannel.pipe[0], &fdread);
-
-        if (!stdinChannel.buffer.isEmpty() && stdinChannel.pipe[1] != -1)
-            add_fd(nfds, stdinChannel.pipe[1], &fdwrite);
+        QProcessPoller poller(*this);

         int timeout = qt_subtract_from_timeout(msecs, stopWatch.elapsed());
 #ifdef Q_OS_BLACKBERRY
         int ret = bb_select(notifiers, nfds + 1, &fdread, &fdwrite, timeout);
 #else
-        int ret = qt_select_msecs(nfds + 1, &fdread, &fdwrite, timeout);
+        int ret = poller.poll(timeout);
 #endif
         if (ret < 0) {
             break;
@@ -889,18 +911,18 @@ bool QProcessPrivate::waitForReadyRead(int msecs)
             return false;
         }

-        if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) {
+        if (qt_pollfd_check(poller.childStartedPipe(), POLLIN)) {
             if (!_q_startupNotification())
                 return false;
         }

         bool readyReadEmitted = false;
-        if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread)) {
+        if (qt_pollfd_check(poller.stdoutPipe(), POLLIN)) {
             bool canRead = _q_canReadStandardOutput();
             if (processChannel == QProcess::StandardOutput && canRead)
                 readyReadEmitted = true;
         }
-        if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread)) {
+        if (qt_pollfd_check(poller.stderrPipe(), POLLIN)) {
             bool canRead = _q_canReadStandardError();
             if (processChannel == QProcess::StandardError && canRead)
                 readyReadEmitted = true;
@@ -908,10 +930,10 @@ bool QProcessPrivate::waitForReadyRead(int msecs)
         if (readyReadEmitted)
             return true;

-        if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
+        if (qt_pollfd_check(poller.stdinPipe(), POLLOUT))
             _q_canWrite();

-        if (forkfd == -1 || FD_ISSET(forkfd, &fdread)) {
+        if (qt_pollfd_check(poller.forkfd(), POLLIN)) {
             if (_q_processDied())
                 return false;
         }
@@ -933,32 +955,13 @@ bool QProcessPrivate::waitForBytesWritten(int msecs)
 #endif

     while (!stdinChannel.buffer.isEmpty()) {
-        fd_set fdread;
-        fd_set fdwrite;
-
-        FD_ZERO(&fdread);
-        FD_ZERO(&fdwrite);
-
-        int nfds = forkfd;
-        FD_SET(forkfd, &fdread);
-
-        if (processState == QProcess::Starting)
-            add_fd(nfds, childStartedPipe[0], &fdread);
-
-        if (stdoutChannel.pipe[0] != -1)
-            add_fd(nfds, stdoutChannel.pipe[0], &fdread);
-        if (stderrChannel.pipe[0] != -1)
-            add_fd(nfds, stderrChannel.pipe[0], &fdread);
-
-
-        if (!stdinChannel.buffer.isEmpty() && stdinChannel.pipe[1] != -1)
-            add_fd(nfds, stdinChannel.pipe[1], &fdwrite);
+        QProcessPoller poller(*this);

         int timeout = qt_subtract_from_timeout(msecs, stopWatch.elapsed());
 #ifdef Q_OS_BLACKBERRY
         int ret = bb_select(notifiers, nfds + 1, &fdread, &fdwrite, timeout);
 #else
-        int ret = qt_select_msecs(nfds + 1, &fdread, &fdwrite, timeout);
+        int ret = poller.poll(timeout);
 #endif
         if (ret < 0) {
             break;
@@ -969,21 +972,21 @@ bool QProcessPrivate::waitForBytesWritten(int msecs)
             return false;
         }

-        if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) {
+        if (qt_pollfd_check(poller.childStartedPipe(), POLLIN)) {
             if (!_q_startupNotification())
                 return false;
         }

-        if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
+        if (qt_pollfd_check(poller.stdinPipe(), POLLOUT))
             return _q_canWrite();

-        if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread))
+        if (qt_pollfd_check(poller.stdoutPipe(), POLLIN))
             _q_canReadStandardOutput();

-        if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread))
+        if (qt_pollfd_check(poller.stderrPipe(), POLLIN))
             _q_canReadStandardError();

-        if (forkfd == -1 || FD_ISSET(forkfd, &fdread)) {
+        if (qt_pollfd_check(poller.forkfd(), POLLIN)) {
             if (_q_processDied())
                 return false;
         }
@@ -1006,32 +1009,13 @@ bool QProcessPrivate::waitForFinished(int msecs)
 #endif

     forever {
-        fd_set fdread;
-        fd_set fdwrite;
-        int nfds = -1;
-
-        FD_ZERO(&fdread);
-        FD_ZERO(&fdwrite);
-
-        if (processState == QProcess::Starting)
-            add_fd(nfds, childStartedPipe[0], &fdread);
-
-        if (stdoutChannel.pipe[0] != -1)
-            add_fd(nfds, stdoutChannel.pipe[0], &fdread);
-        if (stderrChannel.pipe[0] != -1)
-            add_fd(nfds, stderrChannel.pipe[0], &fdread);
-
-        if (processState == QProcess::Running && forkfd != -1)
-            add_fd(nfds, forkfd, &fdread);
-
-        if (!stdinChannel.buffer.isEmpty() && stdinChannel.pipe[1] != -1)
-            add_fd(nfds, stdinChannel.pipe[1], &fdwrite);
+        QProcessPoller poller(*this);

         int timeout = qt_subtract_from_timeout(msecs, stopWatch.elapsed());
 #ifdef Q_OS_BLACKBERRY
         int ret = bb_select(notifiers, nfds + 1, &fdread, &fdwrite, timeout);
 #else
-        int ret = qt_select_msecs(nfds + 1, &fdread, &fdwrite, timeout);
+        int ret = poller.poll(timeout);
 #endif
         if (ret < 0) {
             break;
@@ -1041,20 +1025,20 @@ bool QProcessPrivate::waitForFinished(int msecs)
             return false;
         }

-        if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) {
+        if (qt_pollfd_check(poller.childStartedPipe(), POLLIN)) {
             if (!_q_startupNotification())
                 return false;
         }
-        if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
+        if (qt_pollfd_check(poller.stdinPipe(), POLLOUT))
             _q_canWrite();

-        if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread))
+        if (qt_pollfd_check(poller.stdoutPipe(), POLLIN))
             _q_canReadStandardOutput();

-        if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread))
+        if (qt_pollfd_check(poller.stderrPipe(), POLLIN))
             _q_canReadStandardError();

-        if (forkfd == -1 || FD_ISSET(forkfd, &fdread)) {
+        if (qt_pollfd_check(poller.forkfd(), POLLIN)) {
             if (_q_processDied())
                 return true;
         }
@@ -1064,10 +1048,8 @@ bool QProcessPrivate::waitForFinished(int msecs)

 bool QProcessPrivate::waitForWrite(int msecs)
 {
-    fd_set fdwrite;
-    FD_ZERO(&fdwrite);
-    FD_SET(stdinChannel.pipe[1], &fdwrite);
-    return qt_select_msecs(stdinChannel.pipe[1] + 1, 0, &fdwrite, msecs < 0 ? 0 : msecs) == 1;
+    pollfd pfd = qt_make_pollfd(stdinChannel.pipe[1], POLLOUT);
+    return qt_poll_msecs(&pfd, 1, msecs < 0 ? 0 : msecs) == 1;
 }

 void QProcessPrivate::findExitCode()
diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri
index bc93791..ff64b4e 100644
--- a/src/corelib/kernel/kernel.pri
+++ b/src/corelib/kernel/kernel.pri
@@ -143,8 +143,14 @@ 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
+
     contains(QT_CONFIG, glib) {
         SOURCES += \
             kernel/qeventdispatcher_glib.cpp
diff --git a/src/corelib/kernel/qcore_unix.cpp b/src/corelib/kernel/qcore_unix.cpp
index 5695cb3..2ffc746 100644
--- a/src/corelib/kernel/qcore_unix.cpp
+++ b/src/corelib/kernel/qcore_unix.cpp
@@ -56,6 +56,11 @@

 QT_BEGIN_NAMESPACE

+#if !defined(QT_HAVE_PPOLL) && defined(QT_HAVE_POLLTS)
+# define ppoll pollts
+# define QT_HAVE_PPOLL
+#endif
+
 static inline bool time_update(struct timespec *tv, const struct timespec &start,
                                const struct timespec &timeout)
 {
@@ -85,9 +90,7 @@ int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept,
 #ifndef Q_OS_QNX
         ret = ::pselect(nfds, fdread, fdwrite, fdexcept, &timeout, 0);
 #else
-        timeval timeoutVal;
-        timeoutVal.tv_sec = timeout.tv_sec;
-        timeoutVal.tv_usec = timeout.tv_nsec / 1000;
+        timeval timeoutVal = timespecToTimeval(timeout);
         ret = ::select(nfds, fdread, fdwrite, fdexcept, &timeoutVal);
 #endif
         if (ret != -1 || errno != EINTR)
@@ -102,17 +105,82 @@ int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept,
     }
 }

+static inline struct timespec millisecsToTimespec(const unsigned int ms)
+{
+    struct timespec tv;
+
+    tv.tv_sec = ms / 1000;
+    tv.tv_nsec = (ms % 1000) * 1000 * 1000;
+
+    return tv;
+}
+
 int qt_select_msecs(int nfds, fd_set *fdread, fd_set *fdwrite, int timeout)
 {
     if (timeout < 0)
         return qt_safe_select(nfds, fdread, fdwrite, 0, 0);

-    struct timespec tv;
-    tv.tv_sec = timeout / 1000;
-    tv.tv_nsec = (timeout % 1000) * 1000 * 1000;
+    struct timespec tv = millisecsToTimespec(timeout);
     return qt_safe_select(nfds, fdread, fdwrite, 0, &tv);
 }

+#if !defined(QT_HAVE_PPOLL) && defined(QT_HAVE_POLL)
+static inline int timespecToMillisecs(const struct timespec *ts)
+{
+    return (ts == NULL) ? -1 :
+           (ts->tv_sec * 1000) + (ts->tv_nsec / 1000000);
+}
+#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 defined(QT_HAVE_POLL)
+    return ::poll(fds, nfds, timespecToMillisecs(timeout_ts));
+#else
+    return qt_poll(fds, nfds, timeout_ts);
+#endif
+}
+
+
+/*!
+    \internal
+
+    Behaves as close to POSIX poll(2) as practical but may be implemented
+    using select(2) where necessary. In that case, returns -1 and sets errno
+    to EINVAL if passed any descriptor greater than or equal to FD_SETSIZE.
+*/
+int qt_safe_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts)
+{
+    if (!timeout_ts) {
+        // no timeout -> block forever
+        int ret;
+        EINTR_LOOP(ret, qt_ppoll(fds, nfds, Q_NULLPTR));
+        return ret;
+    }
+
+    timespec start = qt_gettime();
+    timespec timeout = *timeout_ts;
+
+    // loop and recalculate the timeout as needed
+    forever {
+        const int ret = qt_ppoll(fds, nfds, &timeout);
+        if (ret != -1 || errno != EINTR)
+            return ret;
+
+        // recalculate the timeout
+        if (!time_update(&timeout, start, *timeout_ts)) {
+            // timeout during update
+            // or clock reset, fake timeout error
+            return 0;
+        }
+    }
+}
+
 #ifdef Q_OS_BLACKBERRY
 // The BlackBerry event dispatcher uses bps_get_event. Unfortunately, already registered
 // socket notifiers are disabled by a call to select. This is to rearm the standard streams.
diff --git a/src/corelib/kernel/qcore_unix_p.h b/src/corelib/kernel/qcore_unix_p.h
index f80dcb5..fc3f63b 100644
--- a/src/corelib/kernel/qcore_unix_p.h
+++ b/src/corelib/kernel/qcore_unix_p.h
@@ -66,6 +66,12 @@
 #  include <ioLib.h>
 #endif

+#ifdef QT_NO_NATIVE_POLL
+#  include "qpoll_p.h"
+#else
+#  include <poll.h>
+#endif
+
 struct sockaddr;

 #define EINTR_LOOP(var, cmd)                    \
@@ -122,6 +128,14 @@ inline timespec operator*(const timespec &t1, int 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()
 {
     // Set to ignore SIGPIPE once only.
@@ -303,6 +317,27 @@ static inline pid_t qt_safe_waitpid(pid_t pid, int *status, int options)
 timespec qt_gettime() Q_DECL_NOTHROW;
 void qt_nanosleep(timespec amount);

+Q_CORE_EXPORT int qt_safe_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts);
+
+static inline int qt_poll_msecs(struct pollfd *fds, nfds_t nfds, int timeout)
+{
+    timespec ts, *pts = Q_NULLPTR;
+
+    if (timeout >= 0) {
+        ts.tv_sec = timeout / 1000;
+        ts.tv_nsec = (timeout % 1000) * 1000 * 1000;
+        pts = &ts;
+    }
+
+    return qt_safe_poll(fds, nfds, pts);
+}
+
+static inline struct pollfd qt_make_pollfd(int fd, short events)
+{
+    struct pollfd pfd = { fd, events, 0 };
+    return pfd;
+}
+
 Q_CORE_EXPORT int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept,
                                  const struct timespec *tv);

diff --git a/src/corelib/kernel/qeventdispatcher_unix.cpp b/src/corelib/kernel/qeventdispatcher_unix.cpp
index 155f7b7..7d23283 100644
--- a/src/corelib/kernel/qeventdispatcher_unix.cpp
+++ b/src/corelib/kernel/qeventdispatcher_unix.cpp
@@ -59,7 +59,7 @@
 #    define _POSIX_MONOTONIC_CLOCK 1
 #  endif
 #  include <pipeDrv.h>
-#  include <selectLib.h>
+#  include <sys/time.h>
 #endif

 #if (_POSIX_MONOTONIC_CLOCK-0 <= 0) || defined(QT_BOOTSTRAPPED)
@@ -68,6 +68,20 @@

 QT_BEGIN_NAMESPACE

+static const char *socketType(QSocketNotifier::Type type)
+{
+    switch (type) {
+    case QSocketNotifier::Read:
+        return "Read";
+    case QSocketNotifier::Write:
+        return "Write";
+    case QSocketNotifier::Exception:
+        return "Exception";
+    }
+
+    Q_UNREACHABLE();
+}
+
 #if defined(Q_OS_INTEGRITY) || defined(Q_OS_VXWORKS)
 static void initThreadPipeFD(int fd)
 {
@@ -137,8 +151,6 @@ QEventDispatcherUNIXPrivate::QEventDispatcherUNIXPrivate()

     if (pipefail)
         qFatal("QEventDispatcherUNIXPrivate(): Can not continue without a thread pipe");
-
-    sn_highest = -1;
 }

 QEventDispatcherUNIXPrivate::~QEventDispatcherUNIXPrivate()
@@ -163,116 +175,11 @@ QEventDispatcherUNIXPrivate::~QEventDispatcherUNIXPrivate()
     qDeleteAll(timerList);
 }

-int QEventDispatcherUNIXPrivate::doSelect(QEventLoop::ProcessEventsFlags flags, timespec *timeout)
-{
-    Q_Q(QEventDispatcherUNIX);
-
-    // needed in QEventDispatcherUNIX::select()
-    timerList.updateCurrentTime();
-
-    int nsel;
-    do {
-        // Process timers and socket notifiers - the common UNIX stuff
-        int highest = 0;
-        if (! (flags & QEventLoop::ExcludeSocketNotifiers) && (sn_highest >= 0)) {
-            // return the highest fd we can wait for input on
-                sn_vec[0].select_fds = sn_vec[0].enabled_fds;
-                sn_vec[1].select_fds = sn_vec[1].enabled_fds;
-                sn_vec[2].select_fds = sn_vec[2].enabled_fds;
-            highest = sn_highest;
-        } else {
-            FD_ZERO(&sn_vec[0].select_fds);
-            FD_ZERO(&sn_vec[1].select_fds);
-            FD_ZERO(&sn_vec[2].select_fds);
-        }
-
-        int wakeUpFd = initThreadWakeUp();
-        highest = qMax(highest, wakeUpFd);
-
-        nsel = q->select(highest + 1,
-                         &sn_vec[0].select_fds,
-                         &sn_vec[1].select_fds,
-                         &sn_vec[2].select_fds,
-                         timeout);
-    } while (nsel == -1 && (errno == EINTR || errno == EAGAIN));
-
-    if (nsel == -1) {
-        if (errno == EBADF) {
-            // it seems a socket notifier has a bad fd... find out
-            // which one it is and disable it
-            fd_set fdset;
-            timeval tm;
-            tm.tv_sec = tm.tv_usec = 0l;
-
-            for (int type = 0; type < 3; ++type) {
-                QSockNotType::List &list = sn_vec[type].list;
-                if (list.size() == 0)
-                    continue;
-
-                for (int i = 0; i < list.size(); ++i) {
-                    QSockNot *sn = list[i];
-
-                    FD_ZERO(&fdset);
-                    FD_SET(sn->fd, &fdset);
-
-                    int ret = -1;
-                    do {
-                        switch (type) {
-                        case 0: // read
-                            ret = select(sn->fd + 1, &fdset, 0, 0, &tm);
-                            break;
-                        case 1: // write
-                            ret = select(sn->fd + 1, 0, &fdset, 0, &tm);
-                            break;
-                        case 2: // except
-                            ret = select(sn->fd + 1, 0, 0, &fdset, &tm);
-                            break;
-                        }
-                    } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
-
-                    if (ret == -1 && errno == EBADF) {
-                        // disable the invalid socket notifier
-                        static const char *t[] = { "Read", "Write", "Exception" };
-                        qWarning("QSocketNotifier: Invalid socket %d and type '%s', disabling...",
-                                 sn->fd, t[type]);
-                        sn->obj->setEnabled(false);
-                    }
-                }
-            }
-        } else {
-            // EINVAL... shouldn't happen, so let's complain to stderr
-            // and hope someone sends us a bug report
-            perror("select");
-        }
-    }
-
-    int nevents = processThreadWakeUp(nsel);
-
-    // activate socket notifiers
-    if (! (flags & QEventLoop::ExcludeSocketNotifiers) && nsel > 0 && sn_highest >= 0) {
-        // if select says data is ready on any socket, then set the socket notifier
-        // to pending
-        for (int i=0; i<3; i++) {
-            QSockNotType::List &list = sn_vec[i].list;
-            for (int j = 0; j < list.size(); ++j) {
-                QSockNot *sn = list[j];
-                if (FD_ISSET(sn->fd, &sn_vec[i].select_fds))
-                    q->setSocketNotifierPending(sn->obj);
-            }
-        }
-    }
-    return (nevents + q->activateSocketNotifiers());
-}
-
-int QEventDispatcherUNIXPrivate::initThreadWakeUp()
+int QEventDispatcherUNIXPrivate::processThreadWakeUp(const pollfd &pfd)
 {
-    FD_SET(thread_pipe[0], &sn_vec[0].select_fds);
-    return thread_pipe[0];
-}
+    Q_ASSERT(pfd.fd == thread_pipe[0]);

-int QEventDispatcherUNIXPrivate::processThreadWakeUp(int nsel)
-{
-    if (nsel > 0 && FD_ISSET(thread_pipe[0], &sn_vec[0].select_fds)) {
+    if (pfd.revents & POLLIN) {
         // some other thread woke us up... consume the data on the thread pipe so that
         // select doesn't immediately return next time
 #if defined(Q_OS_VXWORKS)
@@ -302,6 +209,80 @@ int QEventDispatcherUNIXPrivate::processThreadWakeUp(int nsel)
     return 0;
 }

+void QEventDispatcherUNIXPrivate::setSocketNotifierPending(QSocketNotifier *notifier)
+{
+    Q_ASSERT(notifier);
+
+    if (pendingNotifiers.contains(notifier))
+        return;
+
+    pendingNotifiers << notifier;
+}
+
+int QEventDispatcherUNIXPrivate::activateTimers()
+{
+    return timerList.activateTimers();
+}
+
+void QEventDispatcherUNIXPrivate::markPendingSocketNotifiers()
+{
+    foreach (const pollfd &pfd, pollfds) {
+        if (pfd.fd < 0 || pfd.revents == 0)
+            continue;
+
+        auto it = socketNotifiers.find(pfd.fd);
+        Q_ASSERT(it != socketNotifiers.end());
+
+        const QSocketNotifierSetUNIX &sn_set = it.value();
+
+        static const struct {
+            QSocketNotifier::Type type;
+            short flags;
+        } notifiers[] = {
+            { QSocketNotifier::Read,      POLLIN  | POLLHUP | POLLERR },
+            { QSocketNotifier::Write,     POLLOUT | POLLHUP | POLLERR },
+            { QSocketNotifier::Exception, POLLPRI | POLLHUP | POLLERR }
+        };
+
+        for (const auto &n : notifiers) {
+            QSocketNotifier *notifier = sn_set.notifiers[n.type];
+
+            if (!notifier)
+                continue;
+
+            if (pfd.revents & POLLNVAL) {
+                qWarning("QSocketNotifier: Invalid socket %d with type %s, disabling...",
+                         it.key(), socketType(n.type));
+                notifier->setEnabled(false);
+            }
+
+            if (pfd.revents & n.flags)
+                setSocketNotifierPending(notifier);
+        }
+    }
+
+    pollfds.resize(0);
+}
+
+int QEventDispatcherUNIXPrivate::activateSocketNotifiers()
+{
+    markPendingSocketNotifiers();
+
+    if (pendingNotifiers.isEmpty())
+        return 0;
+
+    int n_activated = 0;
+    QEvent event(QEvent::SockAct);
+
+    while (!pendingNotifiers.isEmpty()) {
+        QSocketNotifier *notifier = pendingNotifiers.takeFirst();
+        QCoreApplication::sendEvent(notifier, &event);
+        ++n_activated;
+    }
+
+    return n_activated;
+}
+
 QEventDispatcherUNIX::QEventDispatcherUNIX(QObject *parent)
     : QAbstractEventDispatcher(*new QEventDispatcherUNIXPrivate, parent)
 { }
@@ -311,14 +292,7 @@ QEventDispatcherUNIX::QEventDispatcherUNIX(QEventDispatcherUNIXPrivate &dd, QObj
 { }

 QEventDispatcherUNIX::~QEventDispatcherUNIX()
-{
-}
-
-int QEventDispatcherUNIX::select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
-                                 timespec *timeout)
-{
-    return qt_safe_select(nfds, readfds, writefds, exceptfds, timeout);
-}
+{ }

 /*!
     \internal
@@ -390,22 +364,6 @@ QEventDispatcherUNIX::registeredTimers(QObject *object) const
 }

 /*****************************************************************************
- Socket notifier type
- *****************************************************************************/
-QSockNotType::QSockNotType()
-{
-    FD_ZERO(&select_fds);
-    FD_ZERO(&enabled_fds);
-    FD_ZERO(&pending_fds);
-}
-
-QSockNotType::~QSockNotType()
-{
-    for (int i = 0; i < list.size(); ++i)
-        delete list[i];
-}
-
-/*****************************************************************************
  QEventDispatcher implementations for UNIX
  *****************************************************************************/

@@ -413,160 +371,57 @@ void QEventDispatcherUNIX::registerSocketNotifier(QSocketNotifier *notifier)
 {
     Q_ASSERT(notifier);
     int sockfd = notifier->socket();
-    int type = notifier->type();
+    QSocketNotifier::Type type = notifier->type();
 #ifndef QT_NO_DEBUG
-    if (sockfd < 0
-        || unsigned(sockfd) >= FD_SETSIZE) {
-        qWarning("QSocketNotifier: Internal error");
-        return;
-    } else if (notifier->thread() != thread()
-               || thread() != QThread::currentThread()) {
+    if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
         qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread");
         return;
     }
 #endif

     Q_D(QEventDispatcherUNIX);
-    QSockNotType::List &list = d->sn_vec[type].list;
-    fd_set *fds  = &d->sn_vec[type].enabled_fds;
-    QSockNot *sn;
-
-    sn = new QSockNot;
-    sn->obj = notifier;
-    sn->fd = sockfd;
-    sn->queue = &d->sn_vec[type].pending_fds;
-
-    int i;
-    for (i = 0; i < list.size(); ++i) {
-        QSockNot *p = list[i];
-        if (p->fd < sockfd)
-            break;
-        if (p->fd == sockfd) {
-            static const char *t[] = { "Read", "Write", "Exception" };
-            qWarning("QSocketNotifier: Multiple socket notifiers for "
-                      "same socket %d and type %s", sockfd, t[type]);
-        }
-    }
-    list.insert(i, sn);
+    QSocketNotifierSetUNIX &sn_set = d->socketNotifiers[sockfd];
+
+    if (sn_set.notifiers[type] && sn_set.notifiers[type] != notifier)
+        qWarning("%s: Multiple socket notifiers for same socket %d and type %s",
+                 Q_FUNC_INFO, sockfd, socketType(type));

-    FD_SET(sockfd, fds);
-    d->sn_highest = qMax(d->sn_highest, sockfd);
+    sn_set.notifiers[type] = notifier;
 }

 void QEventDispatcherUNIX::unregisterSocketNotifier(QSocketNotifier *notifier)
 {
     Q_ASSERT(notifier);
     int sockfd = notifier->socket();
-    int type = notifier->type();
+    QSocketNotifier::Type type = notifier->type();
 #ifndef QT_NO_DEBUG
-    if (sockfd < 0
-        || unsigned(sockfd) >= FD_SETSIZE) {
-        qWarning("QSocketNotifier: Internal error");
-        return;
-    } else if (notifier->thread() != thread()
-               || thread() != QThread::currentThread()) {
+    if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
         qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread");
         return;
     }
 #endif

     Q_D(QEventDispatcherUNIX);
-    QSockNotType::List &list = d->sn_vec[type].list;
-    fd_set *fds  =  &d->sn_vec[type].enabled_fds;
-    QSockNot *sn = 0;
-    int i;
-    for (i = 0; i < list.size(); ++i) {
-        sn = list[i];
-        if(sn->obj == notifier && sn->fd == sockfd)
-            break;
-    }
-    if (i == list.size()) // not found
-        return;
+    d->pendingNotifiers.removeOne(notifier);

-    FD_CLR(sockfd, fds);                        // clear fd bit
-    FD_CLR(sockfd, sn->queue);
-    d->sn_pending_list.removeAll(sn);                // remove from activation list
-    list.removeAt(i);                                // remove notifier found above
-    delete sn;
-
-    if (d->sn_highest == sockfd) {                // find highest fd
-        d->sn_highest = -1;
-        for (int i=0; i<3; i++) {
-            if (!d->sn_vec[i].list.isEmpty())
-                d->sn_highest = qMax(d->sn_highest,  // list is fd-sorted
-                                     d->sn_vec[i].list[0]->fd);
-        }
-    }
-}
-
-void QEventDispatcherUNIX::setSocketNotifierPending(QSocketNotifier *notifier)
-{
-    Q_ASSERT(notifier);
-    int sockfd = notifier->socket();
-    int type = notifier->type();
-#ifndef QT_NO_DEBUG
-    if (sockfd < 0
-        || unsigned(sockfd) >= FD_SETSIZE) {
-        qWarning("QSocketNotifier: Internal error");
+    auto i = d->socketNotifiers.find(sockfd);
+    if (i == d->socketNotifiers.end())
         return;
-    }
-    Q_ASSERT(notifier->thread() == thread() && thread() == QThread::currentThread());
-#endif
+    QSocketNotifierSetUNIX &sn_set = i.value();

-    Q_D(QEventDispatcherUNIX);
-    QSockNotType::List &list = d->sn_vec[type].list;
-    QSockNot *sn = 0;
-    int i;
-    for (i = 0; i < list.size(); ++i) {
-        sn = list[i];
-        if(sn->obj == notifier && sn->fd == sockfd)
-            break;
-    }
-    if (i == list.size()) // not found
+    if (sn_set.notifiers[type] == nullptr)
         return;

-    // We choose a random activation order to be more fair under high load.
-    // If a constant order is used and a peer early in the list can
-    // saturate the IO, it might grab our attention completely.
-    // Also, if we're using a straight list, the callback routines may
-    // delete other entries from the list before those other entries are
-    // processed.
-    if (! FD_ISSET(sn->fd, sn->queue)) {
-        if (d->sn_pending_list.isEmpty()) {
-            d->sn_pending_list.append(sn);
-        } else {
-            d->sn_pending_list.insert((qrand() & 0xff) %
-                                      (d->sn_pending_list.size()+1), sn);
-        }
-        FD_SET(sn->fd, sn->queue);
+    if (sn_set.notifiers[type] != notifier) {
+        qWarning("%s: Multiple socket notifiers for same socket %d and type %s",
+                 Q_FUNC_INFO, sockfd, socketType(type));
+        return;
     }
-}
-
-int QEventDispatcherUNIX::activateTimers()
-{
-    Q_ASSERT(thread() == QThread::currentThread());
-    Q_D(QEventDispatcherUNIX);
-    return d->timerList.activateTimers();
-}

-int QEventDispatcherUNIX::activateSocketNotifiers()
-{
-    Q_D(QEventDispatcherUNIX);
-    if (d->sn_pending_list.isEmpty())
-        return 0;
+    sn_set.notifiers[type] = nullptr;

-    // activate entries
-    int n_act = 0;
-    QEvent event(QEvent::SockAct);
-    while (!d->sn_pending_list.isEmpty()) {
-        QSockNot *sn = d->sn_pending_list.takeFirst();
-        if (FD_ISSET(sn->fd, sn->queue)) {
-            FD_CLR(sn->fd, sn->queue);
-            QCoreApplication::sendEvent(sn->obj, &event);
-            ++n_act;
-        }
-    }
-    return n_act;
+    if (sn_set.isEmpty())
+        d->socketNotifiers.erase(i);
 }

 bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags)
@@ -578,39 +433,54 @@ bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags)
     emit awake();
     QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData);

-    int nevents = 0;
+    const bool include_timers = (flags & QEventLoop::X11ExcludeTimers) == 0;
+    const bool include_notifiers = (flags & QEventLoop::ExcludeSocketNotifiers) == 0;
+    const bool wait_for_events = flags & QEventLoop::WaitForMoreEvents;
+
     const bool canWait = (d->threadData->canWaitLocked()
                           && !d->interrupt.load()
-                          && (flags & QEventLoop::WaitForMoreEvents));
+                          && wait_for_events);

     if (canWait)
         emit aboutToBlock();

-    if (!d->interrupt.load()) {
-        // return the maximum time we can wait for an event.
-        timespec *tm = 0;
-        timespec wait_tm = { 0l, 0l };
-        if (!(flags & QEventLoop::X11ExcludeTimers)) {
-            if (d->timerList.timerWait(wait_tm))
-                tm = &wait_tm;
-        }
+    if (d->interrupt.load())
+        return false;

-        if (!canWait) {
-            if (!tm)
-                tm = &wait_tm;
+    timespec *tm = nullptr;
+    timespec wait_tm = { 0, 0 };

-            // no time to wait
-            tm->tv_sec  = 0l;
-            tm->tv_nsec = 0l;
-        }
+    if (!canWait || (include_timers && d->timerList.timerWait(wait_tm)))
+        tm = &wait_tm;

-        nevents = d->doSelect(flags, tm);
+    d->pollfds.reserve(1 + (include_notifiers ? d->socketNotifiers.size() : 0));
+    d->pollfds.resize(0);

-        // activate timers
-        if (! (flags & QEventLoop::X11ExcludeTimers)) {
-            nevents += activateTimers();
-        }
+    if (include_notifiers)
+        for (auto it = d->socketNotifiers.cbegin(); it != d->socketNotifiers.cend(); ++it)
+            d->pollfds.append(qt_make_pollfd(it.key(), it.value().events()));
+
+    // This must be last, as it's popped off the end below
+    d->pollfds.append(qt_make_pollfd(d->thread_pipe[0], POLLIN));
+
+    int nevents = 0;
+
+    switch (qt_safe_poll(d->pollfds.data(), d->pollfds.size(), tm)) {
+    case -1:
+        perror("qt_safe_poll");
+        break;
+    case 0:
+        break;
+    default:
+        nevents += d->processThreadWakeUp(d->pollfds.takeLast());
+        if (include_notifiers)
+            nevents += d->activateSocketNotifiers();
+        break;
     }
+
+    if (include_timers)
+        nevents += d->activateTimers();
+
     // return true if we handled events, false otherwise
     return (nevents > 0);
 }
diff --git a/src/corelib/kernel/qeventdispatcher_unix_p.h b/src/corelib/kernel/qeventdispatcher_unix_p.h
index df08080..b76bb8e 100644
--- a/src/corelib/kernel/qeventdispatcher_unix_p.h
+++ b/src/corelib/kernel/qeventdispatcher_unix_p.h
@@ -53,38 +53,21 @@
 #include "QtCore/qvarlengtharray.h"
 #include "private/qtimerinfo_unix_p.h"

-#if !defined(Q_OS_VXWORKS)
-#  include <sys/time.h>
-#  if (!defined(Q_OS_HPUX) || defined(__ia64)) && !defined(Q_OS_NACL)
-#    include <sys/select.h>
-#  endif
-#endif
-
 QT_BEGIN_NAMESPACE

-struct QSockNot
-{
-    QSocketNotifier *obj;
-    int fd;
-    fd_set *queue;
-};
+class QEventDispatcherUNIXPrivate;

-class QSockNotType
+struct Q_CORE_EXPORT QSocketNotifierSetUNIX Q_DECL_FINAL
 {
-public:
-    QSockNotType();
-    ~QSockNotType();
+    inline QSocketNotifierSetUNIX() Q_DECL_NOTHROW;

-    typedef QPodList<QSockNot*, 32> List;
-
-    List list;
-    fd_set select_fds;
-    fd_set enabled_fds;
-    fd_set pending_fds;
+    inline bool isEmpty() const Q_DECL_NOTHROW;
+    inline short events() const Q_DECL_NOTHROW;

+    QSocketNotifier *notifiers[3];
 };

-class QEventDispatcherUNIXPrivate;
+Q_DECLARE_TYPEINFO(QSocketNotifierSetUNIX, Q_PRIMITIVE_TYPE);

 #ifdef Q_OS_QNX
 #  define FINAL_EXCEPT_BLACKBERRY
@@ -120,15 +103,6 @@ public:

 protected:
     QEventDispatcherUNIX(QEventDispatcherUNIXPrivate &dd, QObject *parent = 0);
-
-    void setSocketNotifierPending(QSocketNotifier *notifier);
-
-    int activateTimers();
-    int activateSocketNotifiers();
-
-    virtual int select(int nfds,
-                       fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
-                       timespec *timeout);
 };

 class Q_CORE_EXPORT QEventDispatcherUNIXPrivate : public QAbstractEventDispatcherPrivate
@@ -139,9 +113,13 @@ public:
     QEventDispatcherUNIXPrivate();
     ~QEventDispatcherUNIXPrivate();

-    int doSelect(QEventLoop::ProcessEventsFlags flags, timespec *timeout);
-    virtual int initThreadWakeUp() FINAL_EXCEPT_BLACKBERRY;
-    virtual int processThreadWakeUp(int nsel) FINAL_EXCEPT_BLACKBERRY;
+    int processThreadWakeUp(const pollfd &pfd);
+
+    int activateTimers();
+
+    void markPendingSocketNotifiers();
+    int activateSocketNotifiers();
+    void setSocketNotifierPending(QSocketNotifier *notifier);

     bool mainThread;

@@ -149,15 +127,12 @@ public:
     // if thread_pipe[1] is -1, then eventfd(7) is in use and is stored in thread_pipe[0]
     int thread_pipe[2];

-    // highest fd for all socket notifiers
-    int sn_highest;
-    // 3 socket notifier types - read, write and exception
-    QSockNotType sn_vec[3];
+    QVector<pollfd> pollfds;

-    QTimerInfoList timerList;
+    QHash<int, QSocketNotifierSetUNIX> socketNotifiers;
+    QVector<QSocketNotifier *> pendingNotifiers;

-    // pending socket notifiers list
-    QSockNotType::List sn_pending_list;
+    QTimerInfoList timerList;

     QAtomicInt wakeUps;
     QAtomicInt interrupt; // bool
@@ -165,6 +140,34 @@ public:

 #undef FINAL_EXCEPT_BLACKBERRY

+inline QSocketNotifierSetUNIX::QSocketNotifierSetUNIX() Q_DECL_NOTHROW
+{
+    notifiers[0] = 0;
+    notifiers[1] = 0;
+    notifiers[2] = 0;
+}
+
+inline bool QSocketNotifierSetUNIX::isEmpty() const Q_DECL_NOTHROW
+{
+    return !notifiers[0] && !notifiers[1] && !notifiers[2];
+}
+
+inline short QSocketNotifierSetUNIX::events() const Q_DECL_NOTHROW
+{
+    short result = 0;
+
+    if (notifiers[0])
+        result |= POLLIN;
+
+    if (notifiers[1])
+        result |= POLLOUT;
+
+    if (notifiers[2])
+        result |= POLLPRI;
+
+    return result;
+}
+
 QT_END_NAMESPACE

 #endif // QEVENTDISPATCHER_UNIX_P_H
diff --git a/src/corelib/kernel/qpoll.cpp b/src/corelib/kernel/qpoll.cpp
new file mode 100644
index 0000000..b152518
--- /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 0000000..497058a
--- /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
diff --git a/src/network/socket/qlocalserver_unix.cpp b/src/network/socket/qlocalserver_unix.cpp
index a356e21..79b9b9c 100644
--- a/src/network/socket/qlocalserver_unix.cpp
+++ b/src/network/socket/qlocalserver_unix.cpp
@@ -277,24 +277,27 @@ void QLocalServerPrivate::_q_onNewConnection()

 void QLocalServerPrivate::waitForNewConnection(int msec, bool *timedOut)
 {
-    fd_set readfds;
-    FD_ZERO(&readfds);
-    FD_SET(listenSocket, &readfds);
+    pollfd pfd = qt_make_pollfd(listenSocket, POLLIN);

-    struct timespec timeout;
-    timeout.tv_sec = msec / 1000;
-    timeout.tv_nsec = (msec % 1000) * 1000 * 1000;
+    switch (qt_poll_msecs(&pfd, 1, msec)) {
+    case 0:
+        if (timedOut)
+            *timedOut = true;
+        return;
+        break;
+    default:
+        if ((pfd.revents & POLLNVAL) == 0) {
+            _q_onNewConnection();
+            return;
+        }

-    int result = -1;
-    result = qt_safe_select(listenSocket + 1, &readfds, 0, 0, (msec == -1) ? 0 : &timeout);
-    if (-1 == result) {
+        errno = EBADF;
+        // FALLTHROUGH
+    case -1:
         setError(QLatin1String("QLocalServer::waitForNewConnection"));
         closeServer();
+        break;
     }
-    if (result > 0)
-        _q_onNewConnection();
-    if (timedOut)
-        *timedOut = (result == 0);
 }

 void QLocalServerPrivate::setError(const QString &function)
diff --git a/src/network/socket/qlocalsocket_unix.cpp b/src/network/socket/qlocalsocket_unix.cpp
index bb0f11f..3e85217 100644
--- a/src/network/socket/qlocalsocket_unix.cpp
+++ b/src/network/socket/qlocalsocket_unix.cpp
@@ -507,36 +507,25 @@ void QLocalSocket::setReadBufferSize(qint64 size)
 bool QLocalSocket::waitForConnected(int msec)
 {
     Q_D(QLocalSocket);
+
     if (state() != ConnectingState)
         return (state() == ConnectedState);

-    fd_set fds;
-    FD_ZERO(&fds);
-    FD_SET(d->connectingSocket, &fds);
+    QElapsedTimer timer;
+    timer.start();

-    timeval timeout;
-    timeout.tv_sec = msec / 1000;
-    timeout.tv_usec = (msec % 1000) * 1000;
+    pollfd pfd = qt_make_pollfd(d->connectingSocket, POLLIN);

-    // timeout can not be 0 or else select will return an error.
-    if (0 == msec)
-        timeout.tv_usec = 1000;
+    do {
+        const int timeout = (msec > 0) ? qMax(msec - timer.elapsed(), Q_INT64_C(0)) : msec;
+        const int result = qt_poll_msecs(&pfd, 1, timeout);

-    int result = -1;
-    // on Linux timeout will be updated by select, but _not_ on other systems.
-    QElapsedTimer timer;
-    timer.start();
-    while (state() == ConnectingState
-           && (-1 == msec || timer.elapsed() < msec)) {
-        result = ::select(d->connectingSocket + 1, &fds, 0, 0, &timeout);
-        if (-1 == result && errno != EINTR) {
-            d->errorOccurred( QLocalSocket::UnknownSocketError,
-                    QLatin1String("QLocalSocket::waitForConnected"));
-            break;
-        }
-        if (result > 0)
+        if (result == -1)
+            d->errorOccurred(QLocalSocket::UnknownSocketError,
+                             QLatin1String("QLocalSocket::waitForConnected"));
+        else if (result > 0)
             d->_q_connectToSocket();
-    }
+    } while (state() == ConnectingState && !timer.hasExpired(msec));

     return (state() == ConnectedState);
 }
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp
index 6a740f4..de86f27 100644
--- a/src/network/socket/qnativesocketengine_unix.cpp
+++ b/src/network/socket/qnativesocketengine_unix.cpp
@@ -1256,47 +1256,36 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c

 int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const
 {
-    fd_set fds;
-    FD_ZERO(&fds);
-    FD_SET(socketDescriptor, &fds);
-
-    struct timespec tv;
-    tv.tv_sec = timeout / 1000;
-    tv.tv_nsec = (timeout % 1000) * 1000 * 1000;
-
-    int retval;
-    if (selectForRead)
-        retval = qt_safe_select(socketDescriptor + 1, &fds, 0, 0, timeout < 0 ? 0 : &tv);
-    else
-        retval = qt_safe_select(socketDescriptor + 1, 0, &fds, 0, timeout < 0 ? 0 : &tv);
-
-    return retval;
+    bool dummy;
+    return nativeSelect(timeout, selectForRead, !selectForRead, &dummy, &dummy);
 }

 int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite,
                        bool *selectForRead, bool *selectForWrite) const
 {
-    fd_set fdread;
-    FD_ZERO(&fdread);
+    pollfd pfd = qt_make_pollfd(socketDescriptor, 0);
+
     if (checkRead)
-        FD_SET(socketDescriptor, &fdread);
+        pfd.events |= POLLIN;

-    fd_set fdwrite;
-    FD_ZERO(&fdwrite);
     if (checkWrite)
-        FD_SET(socketDescriptor, &fdwrite);
+        pfd.events |= POLLOUT;

-    struct timespec tv;
-    tv.tv_sec = timeout / 1000;
-    tv.tv_nsec = (timeout % 1000) * 1000 * 1000;
-
-    int ret;
-    ret = qt_safe_select(socketDescriptor + 1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv);
+    const int ret = qt_poll_msecs(&pfd, 1, timeout);

     if (ret <= 0)
         return ret;
-    *selectForRead = FD_ISSET(socketDescriptor, &fdread);
-    *selectForWrite = FD_ISSET(socketDescriptor, &fdwrite);
+
+    if (pfd.revents & POLLNVAL) {
+        errno = EBADF;
+        return -1;
+    }
+
+    static const short read_flags = POLLIN | POLLHUP | POLLERR;
+    static const short write_flags = POLLOUT | POLLERR;
+
+    *selectForRead = ((pfd.revents & read_flags) != 0);
+    *selectForWrite = ((pfd.revents & write_flags) != 0);

     return ret;
 }
diff --git a/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp b/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp
index 8ffe4d8..c528891 100644
--- a/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp
+++ b/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp
@@ -48,6 +48,7 @@ private slots:
     void memberFunctions();
     void implicitConvertibleTypes();
     void runWaitLoop();
+    void pollForIsFinished();
     void recursive();
 #ifndef QT_NO_EXCEPTIONS
     void exceptions();
@@ -353,6 +354,33 @@ void tst_QtConcurrentRun::runWaitLoop()
         run(fn).waitForFinished();
 }

+static bool allFinished(const QList<QFuture<void> > &futures)
+{
+    auto hasNotFinished = [](const QFuture<void> &future) { return !future.isFinished(); };
+    return std::find_if(futures.cbegin(), futures.cend(), hasNotFinished)
+        == futures.constEnd();
+}
+
+static void runFunction()
+{
+    QEventLoop loop;
+    QTimer::singleShot(20, &loop, &QEventLoop::quit);
+    loop.exec();
+}
+
+void tst_QtConcurrentRun::pollForIsFinished()
+{
+    const int numThreads = std::max(4, 2 * QThread::idealThreadCount());
+    QThreadPool::globalInstance()->setMaxThreadCount(numThreads);
+
+    QFutureSynchronizer<void> synchronizer;
+    for (int i = 0; i < numThreads; ++i)
+        synchronizer.addFuture(QtConcurrent::run(&runFunction));
+
+    // same as synchronizer.waitForFinished() but with a timeout
+    QTRY_VERIFY(allFinished(synchronizer.futures()));
+}
+
 QAtomicInt count;

 void recursiveRun(int level)
diff --git a/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp b/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp
index c8bb4cd..9b2bada 100644
--- a/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp
+++ b/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp
@@ -430,11 +430,8 @@ public slots:
         dataSent = serverSocket->waitForBytesWritten(-1);

         if (dataSent) {
-            fd_set fdread;
-            int fd = socket->socketDescriptor();
-            FD_ZERO(&fdread);
-            FD_SET(fd, &fdread);
-            dataReadable = (1 == qt_safe_select(fd + 1, &fdread, 0, 0, 0));
+            pollfd pfd = qt_make_pollfd(socket->socketDescriptor(), POLLIN);
+            dataReadable = (1 == qt_safe_poll(&pfd, 1, nullptr));
         }

         if (!dataReadable) {
diff --git a/tests/manual/qt_poll/qt_poll.pro b/tests/manual/qt_poll/qt_poll.pro
new file mode 100644
index 0000000..beea4d1
--- /dev/null
+++ b/tests/manual/qt_poll/qt_poll.pro
@@ -0,0 +1,7 @@
+CONFIG += testcase
+TARGET = tst_qt_poll
+QT = core-private network testlib
+INCLUDEPATH += ../../../src/corelib/kernel
+SOURCES += \
+    tst_qt_poll.cpp \
+    ../../../src/corelib/kernel/qpoll.cpp
diff --git a/tests/manual/qt_poll/tst_qt_poll.cpp b/tests/manual/qt_poll/tst_qt_poll.cpp
new file mode 100644
index 0000000..56e41e4
--- /dev/null
+++ b/tests/manual/qt_poll/tst_qt_poll.cpp
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite 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 QT_NO_NATIVE_POLL
+#define QT_NO_NATIVE_POLL
+#endif
+
+#include <QtTest/QtTest>
+#include <QtNetwork>
+
+#include <private/qcore_unix_p.h>
+
+QT_BEGIN_NAMESPACE
+// defined in qpoll.cpp
+int qt_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts);
+QT_END_NAMESPACE
+
+class tst_qt_poll : public QObject
+{
+    Q_OBJECT
+
+private slots:
+    void pollout();
+    void pollin();
+    void pollnval();
+    void pollprihup();
+};
+
+void tst_qt_poll::pollout()
+{
+    int fds[2];
+    QCOMPARE(pipe(fds), 0);
+
+    struct pollfd pfd = { fds[1], POLLOUT, 0 };
+    const int nready = qt_poll(&pfd, 1, NULL);
+
+    QCOMPARE(nready, 1);
+    QCOMPARE(pfd.revents, short(POLLOUT));
+
+    qt_safe_close(fds[0]);
+    qt_safe_close(fds[1]);
+}
+
+void tst_qt_poll::pollin()
+{
+    int fds[2];
+    QCOMPARE(pipe(fds), 0);
+
+    const char data = 'Q';
+    QCOMPARE(qt_safe_write(fds[1], &data, 1), 1);
+
+    struct pollfd pfd = { fds[0], POLLIN, 0 };
+    const int nready = qt_poll(&pfd, 1, NULL);
+
+    QCOMPARE(nready, 1);
+    QCOMPARE(pfd.revents, short(POLLIN));
+
+    qt_safe_close(fds[0]);
+    qt_safe_close(fds[1]);
+}
+
+void tst_qt_poll::pollnval()
+{
+    struct pollfd pfd = { 42, POLLOUT, 0 };
+
+    int nready = qt_poll(&pfd, 1, NULL);
+    QCOMPARE(nready, 1);
+    QCOMPARE(pfd.revents, short(POLLNVAL));
+
+    pfd.events = 0;
+    pfd.revents = 0;
+
+    nready = qt_poll(&pfd, 1, NULL);
+    QCOMPARE(nready, 1);
+    QCOMPARE(pfd.revents, short(POLLNVAL));
+}
+
+void tst_qt_poll::pollprihup()
+{
+    QTcpServer server;
+    QTcpSocket client_socket;
+
+    QVERIFY(server.listen(QHostAddress::LocalHost));
+
+    const quint16 server_port = server.serverPort();
+    client_socket.connectToHost(server.serverAddress(), server_port);
+
+    QVERIFY(client_socket.waitForConnected());
+    QVERIFY(server.waitForNewConnection());
+
+    QTcpSocket *server_socket = server.nextPendingConnection();
+    server.close();
+
+    // TCP supports only a single byte of urgent data
+    static const char oob_out = 'Q';
+    QCOMPARE(::send(server_socket->socketDescriptor(), &oob_out, 1, MSG_OOB),
+             ssize_t(1));
+
+    struct pollfd pfd = {
+        int(client_socket.socketDescriptor()),
+        POLLPRI | POLLIN,
+        0
+    };
+    int res = qt_poll(&pfd, 1, NULL);
+
+    QCOMPARE(res, 1);
+    QCOMPARE(pfd.revents, short(POLLPRI | POLLIN));
+
+    char oob_in = 0;
+    // We do not specify MSG_OOB here as SO_OOBINLINE is turned on by default
+    // in the native socket engine
+    QCOMPARE(::recv(client_socket.socketDescriptor(), &oob_in, 1, 0),
+             ssize_t(1));
+    QCOMPARE(oob_in, oob_out);
+
+    server_socket->close();
+    pfd.events = POLLIN;
+    res = qt_poll(&pfd, 1, NULL);
+
+    QCOMPARE(res, 1);
+    QCOMPARE(pfd.revents, short(POLLHUP));
+}
+
+QTEST_APPLESS_MAIN(tst_qt_poll)
+#include "tst_qt_poll.moc"
diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp
index 555ccbf..67a581a 100644
--- a/tools/configure/configureapp.cpp
+++ b/tools/configure/configureapp.cpp
@@ -1733,6 +1733,7 @@ void Configure::applySpecSpecifics()
         dictionary[ "QT_EVDEV" ]            = "no";
         dictionary[ "QT_MTDEV" ]            = "no";
         dictionary[ "FONT_CONFIG" ]         = "auto";
+        dictionary[ "POLL" ]                = "poll";
         dictionary[ "ANGLE" ]               = "no";

         dictionary["DECORATIONS"]           = "default windows styled";
@@ -1758,6 +1759,7 @@ void Configure::applySpecSpecifics()
         dictionary[ "QT_XKBCOMMON" ]        = "no";
         dictionary["ANDROID_STYLE_ASSETS"]  = "yes";
         dictionary[ "STYLE_ANDROID" ]       = "yes";
+        dictionary[ "POLL" ]                = "poll";
     }
 }

@@ -3049,6 +3051,9 @@ void Configure::generateOutputVars()
     if (dictionary["REDUCE_EXPORTS"] == "yes")
         qtConfig += "reduce_exports";

+    if (!dictionary["POLL"].isEmpty())
+        qtConfig += "poll_" + dictionary["POLL"];
+
     // We currently have no switch for QtConcurrent, so add it unconditionally.
     qtConfig += "concurrent";