[qt] - add poll support to fix QAbstractSocket errors with more than 1024 file descriptors, thanks Flor

Than Ngo than at fedoraproject.org
Wed Oct 31 12:20:35 UTC 2012


commit 8e4c02d46d0a63e2fed51ae6de0471e9f9a8e00c
Author: Than Ngo <than at redhat.com>
Date:   Wed Oct 31 13:20:22 2012 +0100

    - add poll support to fix QAbstractSocket errors with more than
      1024 file descriptors, thanks Florian for the patch

 qt-4.8-poll.patch |  804 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 qt.spec           |   10 +-
 2 files changed, 813 insertions(+), 1 deletions(-)
---
diff --git a/qt-4.8-poll.patch b/qt-4.8-poll.patch
new file mode 100644
index 0000000..3c99ccf
--- /dev/null
+++ b/qt-4.8-poll.patch
@@ -0,0 +1,804 @@
+--- a/src/corelib/io/qprocess_unix.cpp	
++++ a/src/corelib/io/qprocess_unix.cpp	
+@@ -139,13 +139,6 @@ static void qt_sa_sigchld_handler(int signum)
+         oldAction(signum);
+ }
+ 
+-static inline void add_fd(int &nfds, int fd, fd_set *fdset)
+-{
+-    FD_SET(fd, fdset);
+-    if ((fd) > nfds)
+-        nfds = fd;
+-}
+-
+ struct QProcessInfo {
+     QProcess *process;
+     int deathPipe;
+@@ -231,9 +224,9 @@ QProcessManager::~QProcessManager()
+ void QProcessManager::run()
+ {
+     forever {
+-        fd_set readset;
+-        FD_ZERO(&readset);
+-        FD_SET(qt_qprocess_deadChild_pipe[0], &readset);
++	pollfd fd;
++	fd.fd = qt_qprocess_deadChild_pipe[0];
++	fd.events = POLLIN;
+ 
+ #if defined (QPROCESS_DEBUG)
+         qDebug() << "QProcessManager::run() waiting for children to die";
+@@ -242,8 +235,8 @@ void QProcessManager::run()
+         // block forever, or until activity is detected on the dead child
+         // pipe. the only other peers are the SIGCHLD signal handler, and the
+         // QProcessManager destructor.
+-        int nselect = select(qt_qprocess_deadChild_pipe[0] + 1, &readset, 0, 0, 0);
+-        if (nselect < 0) {
++        int ret = qt_safe_poll(&fd, 1, -1, /* retry_eintr */ false);
++        if (ret < 0) {
+             if (errno == EINTR)
+                 continue;
+             break;
+@@ -992,17 +985,6 @@ void QProcessPrivate::killProcess()
+         ::kill(pid_t(pid), SIGKILL);
+ }
+ 
+-static int 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 timeval tv;
+-    tv.tv_sec = timeout / 1000;
+-    tv.tv_usec = (timeout % 1000) * 1000;
+-    return qt_safe_select(nfds, fdread, fdwrite, 0, &tv);
+-}
+-
+ /*
+    Returns the difference between msecs and elapsed. If msecs is -1,
+    however, -1 is returned.
+@@ -1025,10 +1007,10 @@ bool QProcessPrivate::waitForStarted(int msecs)
+ 	   childStartedPipe[0]);
+ #endif
+ 
+-    fd_set fds;
+-    FD_ZERO(&fds);
+-    FD_SET(childStartedPipe[0], &fds);
+-    if (select_msecs(childStartedPipe[0] + 1, &fds, 0, msecs) == 0) {
++    pollfd fd;
++    fd.fd = childStartedPipe[0];
++    fd.events = POLLIN;
++    if (qt_safe_poll(&fd, 1, msecs) == 0) {
+         processError = QProcess::Timedout;
+         q->setErrorString(QProcess::tr("Process operation timed out"));
+ #if defined (QPROCESS_DEBUG)
+@@ -1044,6 +1026,47 @@ bool QProcessPrivate::waitForStarted(int msecs)
+     return startedEmitted;
+ }
+ 
++class QProcessFDSet {
++    pollfd fds[5];
++
++    static size_t size()
++    {
++	return sizeof(fds)/sizeof(fds[0]);
++    }
++
++public:
++    QProcessFDSet(QProcessPrivate &proc)
++    {
++	for (size_t i = 0; i < size(); ++i) {
++	    fds[i].fd = -1;
++	    fds[i].events = POLLIN;
++	}
++	death().fd = proc.deathPipe[0];
++
++        if (proc.processState == QProcess::Starting)
++	    started().fd = proc.childStartedPipe[0];
++
++	stdout().fd = proc.stdoutChannel.pipe[0];
++	stderr().fd = proc.stderrChannel.pipe[0];
++
++        if (!proc.writeBuffer.isEmpty()) {
++	    stdin().fd = proc.stdinChannel.pipe[1];
++	    stdin().events = POLLOUT;
++	}
++    }
++
++    int poll(int timeout)
++    {
++	return qt_safe_poll(fds, size(), timeout);
++    }
++
++    pollfd &death() { return fds[0]; }
++    pollfd &started() { return fds[1]; }
++    pollfd &stdout() { return fds[2]; }
++    pollfd &stderr() { return fds[3]; }
++    pollfd &stdin() { return fds[4]; }
++};
++
+ bool QProcessPrivate::waitForReadyRead(int msecs)
+ {
+     Q_Q(QProcess);
+@@ -1055,28 +1078,9 @@ bool QProcessPrivate::waitForReadyRead(int msecs)
+     stopWatch.start();
+ 
+     forever {
+-        fd_set fdread;
+-        fd_set fdwrite;
+-
+-        FD_ZERO(&fdread);
+-        FD_ZERO(&fdwrite);
+-
+-        int nfds = deathPipe[0];
+-        FD_SET(deathPipe[0], &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 (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1)
+-            add_fd(nfds, stdinChannel.pipe[1], &fdwrite);
+-
++	QProcessFDSet fdset(*this);
+         int timeout = qt_timeout_value(msecs, stopWatch.elapsed());
+-        int ret = select_msecs(nfds + 1, &fdread, &fdwrite, timeout);
++        int ret = fdset.poll(timeout);
+         if (ret < 0) {
+             break;
+         }
+@@ -1086,18 +1090,18 @@ bool QProcessPrivate::waitForReadyRead(int msecs)
+ 	    return false;
+ 	}
+ 
+-	if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) {
++	if (qt_readable(fdset.started())) {
+             if (!_q_startupNotification())
+                 return false;
+ 	}
+ 
+         bool readyReadEmitted = false;
+-	if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread)) {
++	if (qt_readable(fdset.stdout())) {
+ 	    bool canRead = _q_canReadStandardOutput();
+             if (processChannel == QProcess::StandardOutput && canRead)
+                 readyReadEmitted = true;
+ 	}
+-	if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread)) {
++	if (qt_readable(fdset.stderr())) {
+ 	    bool canRead = _q_canReadStandardError();
+             if (processChannel == QProcess::StandardError && canRead)
+                 readyReadEmitted = true;
+@@ -1105,13 +1109,13 @@ bool QProcessPrivate::waitForReadyRead(int msecs)
+         if (readyReadEmitted)
+             return true;
+ 
+-	if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
++	if (qt_writable(fdset.stdin()))
+ 	    _q_canWrite();
+ 
+-	if (deathPipe[0] == -1 || FD_ISSET(deathPipe[0], &fdread)) {
++	if (qt_readable(fdset.death())) {
+             if (_q_processDied())
+                 return false;
+-        }
++	}
+     }
+     return false;
+ }
+@@ -1127,29 +1131,9 @@ bool QProcessPrivate::waitForBytesWritten(int msecs)
+     stopWatch.start();
+ 
+     while (!writeBuffer.isEmpty()) {
+-        fd_set fdread;
+-        fd_set fdwrite;
+-
+-        FD_ZERO(&fdread);
+-        FD_ZERO(&fdwrite);
+-
+-        int nfds = deathPipe[0];
+-        FD_SET(deathPipe[0], &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 (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1)
+-            add_fd(nfds, stdinChannel.pipe[1], &fdwrite);
+-
++	QProcessFDSet fdset(*this);
+ 	int timeout = qt_timeout_value(msecs, stopWatch.elapsed());
+-	int ret = select_msecs(nfds + 1, &fdread, &fdwrite, timeout);
++	int ret = fdset.poll(timeout);
+         if (ret < 0) {
+             break;
+         }
+@@ -1160,24 +1144,24 @@ bool QProcessPrivate::waitForBytesWritten(int msecs)
+ 	    return false;
+ 	}
+ 
+-	if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) {
++	if (qt_readable(fdset.started())) {
+ 	    if (!_q_startupNotification())
+ 		return false;
+ 	}
+ 
+-	if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
++	if (qt_writable(fdset.stdin()))
+ 	    return _q_canWrite();
+ 
+-	if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread))
++	if (qt_readable(fdset.stdout()))
+ 	    _q_canReadStandardOutput();
+ 
+-	if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread))
++	if (qt_readable(fdset.stderr()))
+ 	    _q_canReadStandardError();
+ 
+-	if (deathPipe[0] == -1 || FD_ISSET(deathPipe[0], &fdread)) {
+-            if (_q_processDied())
+-                return false;
+-        }
++	if (qt_readable(fdset.death())) {
++	    if (_q_processDied())
++		return false;
++	}
+     }
+ 
+     return false;
+@@ -1194,29 +1178,9 @@ bool QProcessPrivate::waitForFinished(int msecs)
+     stopWatch.start();
+ 
+     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)
+-            add_fd(nfds, deathPipe[0], &fdread);
+-
+-        if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1)
+-            add_fd(nfds, stdinChannel.pipe[1], &fdwrite);
+-
++	QProcessFDSet fdset(*this);
+ 	int timeout = qt_timeout_value(msecs, stopWatch.elapsed());
+-	int ret = select_msecs(nfds + 1, &fdread, &fdwrite, timeout);
++	int ret = fdset.poll(timeout);
+         if (ret < 0) {
+             break;
+         }
+@@ -1226,20 +1190,20 @@ bool QProcessPrivate::waitForFinished(int msecs)
+ 	    return false;
+ 	}
+ 
+-	if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) {
++	if (qt_readable(fdset.started())) {
+ 	    if (!_q_startupNotification())
+ 		return false;
+ 	}
+-	if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
++	if (qt_writable(fdset.stdin()))
+ 	    _q_canWrite();
+ 
+-	if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread))
++	if (qt_readable(fdset.stdout()))
+ 	    _q_canReadStandardOutput();
+ 
+-	if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread))
++	if (qt_readable(fdset.stderr()))
+ 	    _q_canReadStandardError();
+ 
+-	if (deathPipe[0] == -1 || FD_ISSET(deathPipe[0], &fdread)) {
++	if (qt_readable(fdset.death())) {
+             if (_q_processDied())
+                 return true;
+ 	}
+@@ -1249,10 +1213,10 @@ bool QProcessPrivate::waitForFinished(int msecs)
+ 
+ bool QProcessPrivate::waitForWrite(int msecs)
+ {
+-    fd_set fdwrite;
+-    FD_ZERO(&fdwrite);
+-    FD_SET(stdinChannel.pipe[1], &fdwrite);
+-    return select_msecs(stdinChannel.pipe[1] + 1, 0, &fdwrite, msecs < 0 ? 0 : msecs) == 1;
++    pollfd fd;
++    fd.fd = stdinChannel.pipe[1];
++    fd.events = POLLIN;
++    return qt_safe_poll(&fd, 1, msecs);
+ }
+ 
+ void QProcessPrivate::findExitCode()
+--- a/src/corelib/kernel/qcore_unix.cpp	
++++ a/src/corelib/kernel/qcore_unix.cpp	
+@@ -103,4 +103,165 @@ int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept,
+     }
+ }
+ 
++#ifndef Q_OS_VXWORKS
++
++int qt_safe_poll(struct pollfd *fds, int nfds, int timeout_ms, bool retry_eintr)
++{
++    if (nfds == 0)
++	return 0;
++    if (nfds < 0) {
++	errno = EINVAL;
++	return -1;
++    }
++
++    // Retry on ret == 0 if the deadline has not yet passed because
++    // Linux can return early from the syscall, without setting EINTR.
++    if (timeout_ms < 0) {
++	forever {
++	    int ret = ::poll(fds, nfds, -1);
++	    if (ret > 0)
++		return ret;
++	    if (retry_eintr) {
++		if (ret == 0 || ret == -1 && errno == EINTR) {
++		    continue;
++		} else {
++		    return -1;
++		}
++	    }
++	    if (ret == 0) {
++		errno = EINTR;
++		return -1;
++	    }
++	    return ret;
++	}
++    }
++
++    timeval previous = qt_gettime();
++    timeval deadline = previous;
++    deadline.tv_sec += timeout_ms / 1000;
++    deadline.tv_usec += (timeout_ms % 1000) * 1000;
++    if (deadline.tv_usec >= 1000000) {
++	++deadline.tv_sec;
++	deadline.tv_usec -= 1000000;
++    }
++    int remaining = timeout_ms;
++
++    forever {
++	int ret = ::poll(fds, nfds, remaining);
++	if (ret > 0)
++	    return ret;
++	timeval now = qt_gettime();
++	if ((now.tv_sec > deadline.tv_sec // past deadline
++	     || (now.tv_sec == deadline.tv_sec
++		 && now.tv_usec >= deadline.tv_usec))
++	    || (now.tv_sec < previous.tv_sec // time warp
++		|| (now.tv_sec == previous.tv_sec
++		    && now.tv_usec < previous.tv_usec))
++	    || (ret < 0 && (errno != EINTR || !retry_eintr))) // other error
++	    return ret;
++	if (ret == 0 && !retry_eintr) {
++	    errno = EINTR;
++	    return -1;
++	}
++        remaining = (deadline.tv_sec - now.tv_sec) * 1000
++		     + (deadline.tv_usec - now.tv_usec) / 1000;
++	previous = now;
++    }
++}
++
++#else
++
++// Poll emulation for VxWorks.
++
++static int mark_bad_descriptors(pollfd *fds, int nfds)
++{
++    fd_set r;
++    FD_ZERO(&r);
++    struct timeval tv;
++    tv.tv_sec = 0;
++    tv.tv_usec = 0;
++    int ret = 0;
++
++    // Check each descriptor invidually for badness.
++    for (int i = 0; i < nfds; ++i) {
++        pollfd &fd(fds[i]);
++        if (fd.fd >= 0) {
++            FD_SET(fd.fd, &r);
++            int ret = qt_safe_select(fd.fd + 1, &r, NULL, NULL, &tv);
++            FD_CLR(fd.fd, &r);
++            if (ret < 0 && errno == EBADF) {
++                fd.revents = POLLNVAL;
++                ++ret;
++            }
++        }
++    }
++    Q_ASSERT(ret > 0);
++    return ret;
++}
++
++int qt_safe_poll(pollfd *fds, int nfds, int timeout, bool retry_eintr)
++{
++    fd_set r, w;
++    FD_ZERO(&r);
++    FD_ZERO(&w);
++    int maxfd = -1;
++
++    // Extract the watched descriptors.
++    for (int i = 0; i < nfds; ++i) {
++        pollfd &fd(fds[i]);
++        if (fd.fd >= 0 && fd.fd < FD_SETSIZE) {
++            if (fd.events & POLLIN) {
++                FD_SET(fd.fd, &r);
++                if (fd.fd > maxfd)
++                    maxfd = fd.fd;
++            }
++            if (fd.events & POLLOUT) {
++                FD_SET(fd.fd, &w);
++                if (fd.fd > maxfd)
++                    maxfd = fd.fd;
++            }
++        }
++    }
++
++    // If timeout is negative, wait indefinitely for activity.
++    timeval tv;
++    timeval *ptv;
++    if (timeout >= 0) {
++        tv.tv_sec = timeout / 1000;
++        tv.tv_usec = (timeout % 1000) * 1000;
++        ptv = &tv;
++    } else
++        ptv = NULL;
++
++    int ret;
++    if (retry_eintr)
++        ret = qt_safe_select(maxfd + 1, &r, &w, NULL, ptv);
++    else
++        ret = ::select(maxfd + 1, &r, &w, NULL, ptv);
++    if (ret < 0 && errno == EBADF) {
++        return mark_bad_descriptors(fds, nfds);
++    }
++    if (ret <= 0)
++        return ret;
++
++    // Set the revents flags.
++    ret = 0;
++    for (int i = 0; i < nfds; ++i) {
++        pollfd &fd(fds[i]);
++        fd.revents = 0;
++        if (fd.fd >= 0 && fd.fd < FD_SETSIZE) {
++            if ((fd.events & POLLIN) && FD_ISSET(fd.fd, &r))
++                fd.revents |= POLLIN;
++            if ((fd.events & POLLOUT) && FD_ISSET(fd.fd, &w))
++                fd.revents |= POLLOUT;
++            if (fd.revents)
++                ++ret;
++        }
++    }
++    Q_ASSERT(ret > 0);
++    return ret;
++}
++
++#endif
++
+ QT_END_NAMESPACE
+--- a/src/corelib/kernel/qcore_unix_p.h	
++++ a/src/corelib/kernel/qcore_unix_p.h	
+@@ -316,9 +316,42 @@ static inline pid_t qt_safe_waitpid(pid_t pid, int *status, int options)
+ 
+ timeval qt_gettime(); // in qelapsedtimer_mac.cpp or qtimestamp_unix.cpp
+ 
++// Deprecated due to FD_SETSIZE limitation, use qt_safe_poll instead.
+ Q_CORE_EXPORT int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept,
+                                  const struct timeval *tv);
+ 
++#ifndef Q_OS_VXWORKS
++#include <poll.h>
++#else
++
++// Poll emulation for VxWorks.
++
++struct pollfd {
++  int fd;
++  short events;
++  short revents;
++};
++
++#define POLLIN 1
++#define POLLOUT 2
++#define POLLERR 4
++#define POLLHUP 8
++#define POLLNVAL 16
++#endif
++
++inline bool qt_readable(const pollfd &fd)
++{
++  return fd.fd >= 0 && (fd.revents & (POLLIN | POLLHUP | POLLERR | POLLNVAL)) != 0;
++}
++
++inline bool qt_writable(const pollfd &fd)
++{
++  return fd.fd >= 0 && (fd.revents & (POLLOUT | POLLHUP | POLLERR | POLLNVAL)) != 0;
++}
++
++Q_CORE_EXPORT int qt_safe_poll(pollfd *fds, int nfds, int timeout,
++                               bool retry_eintr = true);
++
+ // according to X/OPEN we have to define semun ourselves
+ // we use prefix as on some systems sem.h will have it
+ struct semid_ds;
+--- a/src/network/socket/qlocalserver_unix.cpp	
++++ a/src/network/socket/qlocalserver_unix.cpp	
+@@ -208,16 +208,11 @@ void QLocalServerPrivate::_q_onNewConnection()
+ 
+ void QLocalServerPrivate::waitForNewConnection(int msec, bool *timedOut)
+ {
+-    fd_set readfds;
+-    FD_ZERO(&readfds);
+-    FD_SET(listenSocket, &readfds);
++    struct pollfd fd;
++    fd.fd = listenSocket;
++    fd.events = POLLIN;
+ 
+-    timeval timeout;
+-    timeout.tv_sec = msec / 1000;
+-    timeout.tv_usec = (msec % 1000) * 1000;
+-
+-    int result = -1;
+-    result = qt_safe_select(listenSocket + 1, &readfds, 0, 0, (msec == -1) ? 0 : &timeout);
++    int result = qt_safe_poll(&fd, 1, msec);
+     if (-1 == result) {
+         setError(QLatin1String("QLocalServer::waitForNewConnection"));
+         closeServer();
+--- a/src/network/socket/qlocalsocket_unix.cpp	
++++ a/src/network/socket/qlocalsocket_unix.cpp	
+@@ -56,10 +56,6 @@ 
+ #include <qdebug.h>
+ #include <qelapsedtimer.h>
+ 
+-#ifdef Q_OS_VXWORKS
+-#  include <selectLib.h>
+-#endif
+-
+ #define QT_CONNECT_TIMEOUT 30000
+ 
+ QT_BEGIN_NAMESPACE
+@@ -520,32 +516,17 @@ bool QLocalSocket::waitForConnected(int msec)
+     if (state() != ConnectingState)
+         return (state() == ConnectedState);
+ 
+-    fd_set fds;
+-    FD_ZERO(&fds);
+-    FD_SET(d->connectingSocket, &fds);
+-
+-    timeval timeout;
+-    timeout.tv_sec = msec / 1000;
+-    timeout.tv_usec = (msec % 1000) * 1000;
+-
+-    // timeout can not be 0 or else select will return an error.
+-    if (0 == msec)
+-        timeout.tv_usec = 1000;
++    pollfd fd;
++    fd.fd = d->connectingSocket;
++    fd.events = POLLIN | POLLOUT;
+ 
+     int result = -1;
+     // on Linux timeout will be updated by select, but _not_ on other systems.
+     QElapsedTimer timer;
++    int remaining = msec;
+     timer.start();
+-    while (state() == ConnectingState
+-           && (-1 == msec || timer.elapsed() < msec)) {
+-#ifdef Q_OS_SYMBIAN
+-        // On Symbian, ready-to-write is signaled when non-blocking socket
+-        // connect is finised. Is ready-to-read really used on other
+-        // UNIX paltforms when using non-blocking AF_UNIX socket?
+-        result = ::select(d->connectingSocket + 1, 0, &fds, 0, &timeout);
+-#else
+-        result = ::select(d->connectingSocket + 1, &fds, 0, 0, &timeout);
+-#endif
++    while (state() == ConnectingState) {
++        result = qt_safe_poll(&fd, 1, remaining, /* retry_eintr */ false);
+         if (-1 == result && errno != EINTR) {
+             d->errorOccurred( QLocalSocket::UnknownSocketError,
+                     QLatin1String("QLocalSocket::waitForConnected"));
+@@ -553,6 +534,11 @@ bool QLocalSocket::waitForConnected(int msec)
+         }
+         if (result > 0)
+             d->_q_connectToSocket();
++        if (msec >= 0) {
++            remaining = timer.elapsed() - msec;
++            if (remaining < 0)
++                break;
++        }
+     }
+ 
+     return (state() == ConnectedState);
+--- a/src/network/socket/qnativesocketengine_unix.cpp	
++++ a/src/network/socket/qnativesocketengine_unix.cpp	
+@@ -1090,48 +1090,40 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize)
+ 
+ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const
+ {
+-    fd_set fds;
+-    FD_ZERO(&fds);
+-    FD_SET(socketDescriptor, &fds);
+-
+-    struct timeval tv;
+-    tv.tv_sec = timeout / 1000;
+-    tv.tv_usec = (timeout % 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;
++    struct pollfd fd;
++    fd.fd = socketDescriptor;
++    if (selectForRead) {
++	fd.events = POLLIN;
++    } else {
++	fd.events = POLLOUT;
++    }
++    return qt_safe_poll(&fd, 1, timeout);
+ }
+ 
+ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite,
+                        bool *selectForRead, bool *selectForWrite) const
+ {
+-    fd_set fdread;
+-    FD_ZERO(&fdread);
++    struct pollfd fd;
++    fd.fd = socketDescriptor;
+     if (checkRead)
+-        FD_SET(socketDescriptor, &fdread);
+-
+-    fd_set fdwrite;
+-    FD_ZERO(&fdwrite);
++	fd.events =  POLLIN;
++    else
++	fd.events = 0;
+     if (checkWrite)
+-        FD_SET(socketDescriptor, &fdwrite);
+-
+-    struct timeval tv;
+-    tv.tv_sec = timeout / 1000;
+-    tv.tv_usec = (timeout % 1000) * 1000;
+-
+-    int ret;
+-    ret = qt_safe_select(socketDescriptor + 1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv);
+-
++	fd.events |= POLLOUT;
++    int ret = qt_safe_poll(&fd, 1, timeout);
+     if (ret <= 0)
+-        return ret;
+-    *selectForRead = FD_ISSET(socketDescriptor, &fdread);
+-    *selectForWrite = FD_ISSET(socketDescriptor, &fdwrite);
+-
++	return ret;
++    bool r = (fd.revents & (POLLIN | POLLHUP | POLLERR)) != 0;
++    bool w = (fd.revents & (POLLOUT | POLLHUP | POLLERR)) != 0;
++    // Emulate the return value from select(2).
++    ret = 0;
++    if (r)
++	++ret;
++    if (w)
++	++ret;
++    *selectForRead = r;
++    *selectForWrite = w;
+     return ret;
+ }
+ 
+--- a/src/qt3support/network/q3socketdevice_unix.cpp	
++++ a/src/qt3support/network/q3socketdevice_unix.cpp	
+@@ -68,6 +68,7 @@ static inline int qt_socket_socket(int domain, int type, int protocol)
+ #endif
+ 
+ #include "q3socketdevice.h"
++#include "private/qcore_unix_p.h"
+ 
+ #ifndef QT_NO_NETWORK
+ 
+@@ -588,19 +589,10 @@ Q_LONG Q3SocketDevice::waitForMore( int msecs, bool *timeout ) const
+ {
+     if ( !isValid() )
+ 	return -1;
+-    if ( fd >= FD_SETSIZE )
+-	return -1;
+-
+-    fd_set fds;
+-    struct timeval tv;
+-
+-    FD_ZERO( &fds );
+-    FD_SET( fd, &fds );
+-
+-    tv.tv_sec = msecs / 1000;
+-    tv.tv_usec = (msecs % 1000) * 1000;
+ 
+-    int rv = select( fd+1, &fds, 0, 0, msecs < 0 ? 0 : &tv );
++    pollfd pfd;
++    pfd.fd = fd;
++    int rv = qt_safe_poll(&pfd, 1, msecs, /* retry_eintr */ false);
+ 
+     if ( rv < 0 )
+ 	return -1;
+--- a/src/qt3support/other/q3process_unix.cpp	
++++ a/src/qt3support/other/q3process_unix.cpp	
+@@ -981,13 +981,10 @@ bool Q3Process::isRunning() const
+ 	// On heavy processing, the socket notifier for the sigchild might not
+ 	// have found time to fire yet.
+ 	if ( d->procManager && d->procManager->sigchldFd[1] < FD_SETSIZE ) {
+-	    fd_set fds;
+-	    struct timeval tv;
+-	    FD_ZERO( &fds );
+-	    FD_SET( d->procManager->sigchldFd[1], &fds );
+-	    tv.tv_sec = 0;
+-	    tv.tv_usec = 0;
+-	    if ( ::select( d->procManager->sigchldFd[1]+1, &fds, 0, 0, &tv ) > 0 )
++	    pollfd fd;
++	    fd.fd = d->procManager->sigchldFd[1];
++	    fd.events = POLLIN;
++	    if ( qt_safe_poll(&fd, 1, 0, /* retry_eintr */ false) > 0 )
+ 		d->procManager->sigchldHnd( d->procManager->sigchldFd[1] );
+ 	}
+ 
+@@ -1124,29 +1121,21 @@ void Q3Process::socketRead( int fd )
+ 	}
+     }
+ 
+-    if ( fd < FD_SETSIZE ) {
+-	fd_set fds;
+-	struct timeval tv;
+-	FD_ZERO( &fds );
+-	FD_SET( fd, &fds );
+-	tv.tv_sec = 0;
+-	tv.tv_usec = 0;
+-	while ( ::select( fd+1, &fds, 0, 0, &tv ) > 0 ) {
+-	    // prepare for the next round
+-	    FD_ZERO( &fds );
+-	    FD_SET( fd, &fds );
+-	    // read data
+-	    ba = new QByteArray( basize );
+-	    n = ::read( fd, ba->data(), basize );
+-	    if ( n > 0 ) {
+-		ba->resize( n );
+-		buffer->append( ba );
+-		ba = 0;
+-	    } else {
+-		delete ba;
+-		ba = 0;
+-		break;
+-	    }
++    pollfd pfd;
++    pfd.fd = fd;
++    pfd.events = POLLIN;
++    while (qt_safe_poll(&pfd, 1, 0)) {
++	// read data
++	ba = new QByteArray( basize );
++	n = ::read( fd, ba->data(), basize );
++	if ( n > 0 ) {
++	    ba->resize( n );
++	    buffer->append( ba );
++	    ba = 0;
++	} else {
++	    delete ba;
++	    ba = 0;
++	    break;
+ 	}
+     }
+ 
diff --git a/qt.spec b/qt.spec
index 213130a..c1a79ed 100644
--- a/qt.spec
+++ b/qt.spec
@@ -16,7 +16,7 @@ Summary: Qt toolkit
 Name:    qt
 Epoch:   1
 Version: 4.8.3
-Release: 7%{?dist}
+Release: 8%{?dist}
 
 # See LGPL_EXCEPTIONS.txt, LICENSE.GPL3, respectively, for exception details
 License: (LGPLv2 with exceptions or GPLv3 with exceptions) and ASL 2.0 and BSD and FTL and MIT
@@ -116,6 +116,9 @@ Patch81: qt-everywhere-opensource-src-4.8.2--assistant-crash.patch
 # QDir::homePath() should account for an empty HOME environment variable on X11
 Patch82: qt-everywhere-opensource-src-4.8.3-QTBUG-4862.patch
 
+# poll support
+Patch83: qt-4.8-poll.patch
+
 # upstream patches
 # http://codereview.qt-project.org/#change,22006
 Patch100: qt-everywhere-opensource-src-4.8.1-qtgahandle.patch
@@ -466,6 +469,7 @@ rm -fv mkspecs/linux-g++*/qmake.conf.multilib-optflags
 %patch80 -p1 -b .ld.gold
 %patch81 -p1 -b .assistant-crash
 %patch82 -p1 -b .QTBUG-4862
+%patch83 -p1 -b .poll
 
 # upstream patches
 %patch100 -p1 -b .QTgaHandler
@@ -1109,6 +1113,10 @@ fi
 
 
 %changelog
+* Wed Oct 31 2012 Than Ngo <than at redhat.com> - 1:4.8.3-8
+- add poll support to fix QAbstractSocket errors with more than
+  1024 file descriptors, thanks Florian for the patch
+
 * Wed Oct 24 2012 Rex Dieter <rdieter at fedoraproject.org> 1:4.8.3-7
 - Crash in Qt script (QTBUG-27322)
 


More information about the scm-commits mailing list