|
|
2d44415 |
commit 8a2d9073e959356808ce1685822b839d880e6498
|
|
|
2d44415 |
Author: Florian Weimer <fweimer@redhat.com>
|
|
|
2d44415 |
Date: Fri Sep 14 17:27:35 2012 +0200
|
|
|
2d44415 |
|
|
|
2d44415 |
Replace most calls to select(2) with poll(2)
|
|
|
2d44415 |
|
|
|
2d44415 |
select(2) limits the number of file descriptor in a process to
|
|
|
2d44415 |
FD_SETSIZE (typically 1023). Process creation and certain socket
|
|
|
2d44415 |
operations fail because they call select(2) on a file descriptor outside
|
|
|
2d44415 |
the FD_SETSIZE range.
|
|
|
2d44415 |
|
|
|
2d44415 |
The remaining select(2) calls are used for timeouts only, or are in the
|
|
|
2d44415 |
traditional event loop. The glib-based event loop does not use
|
|
|
2d44415 |
select(2), so this should be sufficient.
|
|
|
2d44415 |
|
|
|
2d44415 |
This change adds a poll emulation for VxWorks, which only offers
|
|
|
2d44415 |
select(2).
|
|
|
2d44415 |
|
|
|
2d44415 |
Change-Id: I9b0cf5bec81da70b29c501c62d14fb57df87fa61
|
|
|
2d44415 |
|
|
|
2d44415 |
diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp
|
|
|
2d44415 |
index e159bf8..bb8a3ae 100644
|
|
|
2d44415 |
--- a/src/corelib/io/qprocess_unix.cpp
|
|
|
2d44415 |
+++ b/src/corelib/io/qprocess_unix.cpp
|
|
|
2d44415 |
@@ -134,13 +134,6 @@ static void qt_sa_sigchld_handler(int signum)
|
|
|
2d44415 |
oldAction(signum);
|
|
|
2d44415 |
}
|
|
|
2d44415 |
|
|
|
2d44415 |
-static inline void add_fd(int &nfds, int fd, fd_set *fdset)
|
|
|
2d44415 |
-{
|
|
|
2d44415 |
- FD_SET(fd, fdset);
|
|
|
2d44415 |
- if ((fd) > nfds)
|
|
|
2d44415 |
- nfds = fd;
|
|
|
2d44415 |
-}
|
|
|
2d44415 |
-
|
|
|
2d44415 |
struct QProcessInfo {
|
|
|
2d44415 |
QProcess *process;
|
|
|
2d44415 |
int deathPipe;
|
|
|
2d44415 |
@@ -235,9 +228,9 @@ QProcessManager::~QProcessManager()
|
|
|
2d44415 |
void QProcessManager::run()
|
|
|
2d44415 |
{
|
|
|
2d44415 |
forever {
|
|
|
2d44415 |
- fd_set readset;
|
|
|
2d44415 |
- FD_ZERO(&readset);
|
|
|
2d44415 |
- FD_SET(qt_qprocess_deadChild_pipe[0], &readset);
|
|
|
2d44415 |
+ pollfd fd;
|
|
|
2d44415 |
+ fd.fd = qt_qprocess_deadChild_pipe[0];
|
|
|
2d44415 |
+ fd.events = POLLIN;
|
|
|
2d44415 |
|
|
|
2d44415 |
#if defined (QPROCESS_DEBUG)
|
|
|
2d44415 |
qDebug() << "QProcessManager::run() waiting for children to die";
|
|
|
2d44415 |
@@ -246,8 +239,8 @@ void QProcessManager::run()
|
|
|
2d44415 |
// block forever, or until activity is detected on the dead child
|
|
|
2d44415 |
// pipe. the only other peers are the SIGCHLD signal handler, and the
|
|
|
2d44415 |
// QProcessManager destructor.
|
|
|
2d44415 |
- int nselect = select(qt_qprocess_deadChild_pipe[0] + 1, &readset, 0, 0, 0);
|
|
|
2d44415 |
- if (nselect < 0) {
|
|
|
2d44415 |
+ int ret = qt_safe_poll(&fd, 1, -1, /* retry_eintr */ false);
|
|
|
2d44415 |
+ if (ret < 0) {
|
|
|
2d44415 |
if (errno == EINTR)
|
|
|
2d44415 |
continue;
|
|
|
2d44415 |
break;
|
|
|
2d44415 |
@@ -996,17 +989,6 @@ void QProcessPrivate::killProcess()
|
|
|
2d44415 |
::kill(pid_t(pid), SIGKILL);
|
|
|
2d44415 |
}
|
|
|
2d44415 |
|
|
|
2d44415 |
-static int select_msecs(int nfds, fd_set *fdread, fd_set *fdwrite, int timeout)
|
|
|
2d44415 |
-{
|
|
|
2d44415 |
- if (timeout < 0)
|
|
|
2d44415 |
- return qt_safe_select(nfds, fdread, fdwrite, 0, 0);
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- struct timeval tv;
|
|
|
2d44415 |
- tv.tv_sec = timeout / 1000;
|
|
|
2d44415 |
- tv.tv_usec = (timeout % 1000) * 1000;
|
|
|
2d44415 |
- return qt_safe_select(nfds, fdread, fdwrite, 0, &tv;;
|
|
|
2d44415 |
-}
|
|
|
2d44415 |
-
|
|
|
2d44415 |
/*
|
|
|
2d44415 |
Returns the difference between msecs and elapsed. If msecs is -1,
|
|
|
2d44415 |
however, -1 is returned.
|
|
|
2d44415 |
@@ -1029,10 +1011,10 @@ bool QProcessPrivate::waitForStarted(int msecs)
|
|
|
2d44415 |
childStartedPipe[0]);
|
|
|
2d44415 |
#endif
|
|
|
2d44415 |
|
|
|
2d44415 |
- fd_set fds;
|
|
|
2d44415 |
- FD_ZERO(&fds);
|
|
|
2d44415 |
- FD_SET(childStartedPipe[0], &fds);
|
|
|
2d44415 |
- if (select_msecs(childStartedPipe[0] + 1, &fds, 0, msecs) == 0) {
|
|
|
2d44415 |
+ pollfd fd;
|
|
|
2d44415 |
+ fd.fd = childStartedPipe[0];
|
|
|
2d44415 |
+ fd.events = POLLIN;
|
|
|
2d44415 |
+ if (qt_safe_poll(&fd, 1, msecs) == 0) {
|
|
|
2d44415 |
processError = QProcess::Timedout;
|
|
|
2d44415 |
q->setErrorString(QProcess::tr("Process operation timed out"));
|
|
|
2d44415 |
#if defined (QPROCESS_DEBUG)
|
|
|
2d44415 |
@@ -1048,6 +1030,47 @@ bool QProcessPrivate::waitForStarted(int msecs)
|
|
|
2d44415 |
return startedEmitted;
|
|
|
2d44415 |
}
|
|
|
2d44415 |
|
|
|
2d44415 |
+class QProcessFDSet {
|
|
|
2d44415 |
+ pollfd fds[5];
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+ static size_t size()
|
|
|
2d44415 |
+ {
|
|
|
2d44415 |
+ return sizeof(fds)/sizeof(fds[0]);
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+public:
|
|
|
2d44415 |
+ QProcessFDSet(QProcessPrivate &proc)
|
|
|
2d44415 |
+ {
|
|
|
2d44415 |
+ for (size_t i = 0; i < size(); ++i) {
|
|
|
2d44415 |
+ fds[i].fd = -1;
|
|
|
2d44415 |
+ fds[i].events = POLLIN;
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+ death().fd = proc.deathPipe[0];
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+ if (proc.processState == QProcess::Starting)
|
|
|
2d44415 |
+ started().fd = proc.childStartedPipe[0];
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+ stdout().fd = proc.stdoutChannel.pipe[0];
|
|
|
2d44415 |
+ stderr().fd = proc.stderrChannel.pipe[0];
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+ if (!proc.writeBuffer.isEmpty()) {
|
|
|
2d44415 |
+ stdin().fd = proc.stdinChannel.pipe[1];
|
|
|
2d44415 |
+ stdin().events = POLLOUT;
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+ int poll(int timeout)
|
|
|
2d44415 |
+ {
|
|
|
2d44415 |
+ return qt_safe_poll(fds, size(), timeout);
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+ pollfd &death() { return fds[0]; }
|
|
|
2d44415 |
+ pollfd &started() { return fds[1]; }
|
|
|
2d44415 |
+ pollfd &stdout() { return fds[2]; }
|
|
|
2d44415 |
+ pollfd &stderr() { return fds[3]; }
|
|
|
2d44415 |
+ pollfd &stdin() { return fds[4]; }
|
|
|
2d44415 |
+};
|
|
|
2d44415 |
+
|
|
|
2d44415 |
bool QProcessPrivate::waitForReadyRead(int msecs)
|
|
|
2d44415 |
{
|
|
|
2d44415 |
Q_Q(QProcess);
|
|
|
2d44415 |
@@ -1059,28 +1082,9 @@ bool QProcessPrivate::waitForReadyRead(int msecs)
|
|
|
2d44415 |
stopWatch.start();
|
|
|
2d44415 |
|
|
|
2d44415 |
forever {
|
|
|
2d44415 |
- fd_set fdread;
|
|
|
2d44415 |
- fd_set fdwrite;
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- FD_ZERO(&fdread);
|
|
|
2d44415 |
- FD_ZERO(&fdwrite);
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- int nfds = deathPipe[0];
|
|
|
2d44415 |
- FD_SET(deathPipe[0], &fdread);
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- if (processState == QProcess::Starting)
|
|
|
2d44415 |
- add_fd(nfds, childStartedPipe[0], &fdread);
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- if (stdoutChannel.pipe[0] != -1)
|
|
|
2d44415 |
- add_fd(nfds, stdoutChannel.pipe[0], &fdread);
|
|
|
2d44415 |
- if (stderrChannel.pipe[0] != -1)
|
|
|
2d44415 |
- add_fd(nfds, stderrChannel.pipe[0], &fdread);
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1)
|
|
|
2d44415 |
- add_fd(nfds, stdinChannel.pipe[1], &fdwrite);
|
|
|
2d44415 |
-
|
|
|
2d44415 |
+ QProcessFDSet fdset(*this);
|
|
|
2d44415 |
int timeout = qt_timeout_value(msecs, stopWatch.elapsed());
|
|
|
2d44415 |
- int ret = select_msecs(nfds + 1, &fdread, &fdwrite, timeout);
|
|
|
2d44415 |
+ int ret = fdset.poll(timeout);
|
|
|
2d44415 |
if (ret < 0) {
|
|
|
2d44415 |
break;
|
|
|
2d44415 |
}
|
|
|
2d44415 |
@@ -1090,18 +1094,18 @@ bool QProcessPrivate::waitForReadyRead(int msecs)
|
|
|
2d44415 |
return false;
|
|
|
2d44415 |
}
|
|
|
2d44415 |
|
|
|
2d44415 |
- if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) {
|
|
|
2d44415 |
+ if (qt_readable(fdset.started())) {
|
|
|
2d44415 |
if (!_q_startupNotification())
|
|
|
2d44415 |
return false;
|
|
|
2d44415 |
}
|
|
|
2d44415 |
|
|
|
2d44415 |
bool readyReadEmitted = false;
|
|
|
2d44415 |
- if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread)) {
|
|
|
2d44415 |
+ if (qt_readable(fdset.stdout())) {
|
|
|
2d44415 |
bool canRead = _q_canReadStandardOutput();
|
|
|
2d44415 |
if (processChannel == QProcess::StandardOutput && canRead)
|
|
|
2d44415 |
readyReadEmitted = true;
|
|
|
2d44415 |
}
|
|
|
2d44415 |
- if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread)) {
|
|
|
2d44415 |
+ if (qt_readable(fdset.stderr())) {
|
|
|
2d44415 |
bool canRead = _q_canReadStandardError();
|
|
|
2d44415 |
if (processChannel == QProcess::StandardError && canRead)
|
|
|
2d44415 |
readyReadEmitted = true;
|
|
|
2d44415 |
@@ -1109,13 +1113,13 @@ bool QProcessPrivate::waitForReadyRead(int msecs)
|
|
|
2d44415 |
if (readyReadEmitted)
|
|
|
2d44415 |
return true;
|
|
|
2d44415 |
|
|
|
2d44415 |
- if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
|
|
|
2d44415 |
+ if (qt_writable(fdset.stdin()))
|
|
|
2d44415 |
_q_canWrite();
|
|
|
2d44415 |
|
|
|
2d44415 |
- if (deathPipe[0] == -1 || FD_ISSET(deathPipe[0], &fdread)) {
|
|
|
2d44415 |
+ if (qt_readable(fdset.death())) {
|
|
|
2d44415 |
if (_q_processDied())
|
|
|
2d44415 |
return false;
|
|
|
2d44415 |
- }
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
}
|
|
|
2d44415 |
return false;
|
|
|
2d44415 |
}
|
|
|
2d44415 |
@@ -1131,29 +1135,9 @@ bool QProcessPrivate::waitForBytesWritten(int msecs)
|
|
|
2d44415 |
stopWatch.start();
|
|
|
2d44415 |
|
|
|
2d44415 |
while (!writeBuffer.isEmpty()) {
|
|
|
2d44415 |
- fd_set fdread;
|
|
|
2d44415 |
- fd_set fdwrite;
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- FD_ZERO(&fdread);
|
|
|
2d44415 |
- FD_ZERO(&fdwrite);
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- int nfds = deathPipe[0];
|
|
|
2d44415 |
- FD_SET(deathPipe[0], &fdread);
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- if (processState == QProcess::Starting)
|
|
|
2d44415 |
- add_fd(nfds, childStartedPipe[0], &fdread);
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- if (stdoutChannel.pipe[0] != -1)
|
|
|
2d44415 |
- add_fd(nfds, stdoutChannel.pipe[0], &fdread);
|
|
|
2d44415 |
- if (stderrChannel.pipe[0] != -1)
|
|
|
2d44415 |
- add_fd(nfds, stderrChannel.pipe[0], &fdread);
|
|
|
2d44415 |
-
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1)
|
|
|
2d44415 |
- add_fd(nfds, stdinChannel.pipe[1], &fdwrite);
|
|
|
2d44415 |
-
|
|
|
2d44415 |
+ QProcessFDSet fdset(*this);
|
|
|
2d44415 |
int timeout = qt_timeout_value(msecs, stopWatch.elapsed());
|
|
|
2d44415 |
- int ret = select_msecs(nfds + 1, &fdread, &fdwrite, timeout);
|
|
|
2d44415 |
+ int ret = fdset.poll(timeout);
|
|
|
2d44415 |
if (ret < 0) {
|
|
|
2d44415 |
break;
|
|
|
2d44415 |
}
|
|
|
2d44415 |
@@ -1164,24 +1148,24 @@ bool QProcessPrivate::waitForBytesWritten(int msecs)
|
|
|
2d44415 |
return false;
|
|
|
2d44415 |
}
|
|
|
2d44415 |
|
|
|
2d44415 |
- if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) {
|
|
|
2d44415 |
+ if (qt_readable(fdset.started())) {
|
|
|
2d44415 |
if (!_q_startupNotification())
|
|
|
2d44415 |
return false;
|
|
|
2d44415 |
}
|
|
|
2d44415 |
|
|
|
2d44415 |
- if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
|
|
|
2d44415 |
+ if (qt_writable(fdset.stdin()))
|
|
|
2d44415 |
return _q_canWrite();
|
|
|
2d44415 |
|
|
|
2d44415 |
- if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread))
|
|
|
2d44415 |
+ if (qt_readable(fdset.stdout()))
|
|
|
2d44415 |
_q_canReadStandardOutput();
|
|
|
2d44415 |
|
|
|
2d44415 |
- if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread))
|
|
|
2d44415 |
+ if (qt_readable(fdset.stderr()))
|
|
|
2d44415 |
_q_canReadStandardError();
|
|
|
2d44415 |
|
|
|
2d44415 |
- if (deathPipe[0] == -1 || FD_ISSET(deathPipe[0], &fdread)) {
|
|
|
2d44415 |
- if (_q_processDied())
|
|
|
2d44415 |
- return false;
|
|
|
2d44415 |
- }
|
|
|
2d44415 |
+ if (qt_readable(fdset.death())) {
|
|
|
2d44415 |
+ if (_q_processDied())
|
|
|
2d44415 |
+ return false;
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
}
|
|
|
2d44415 |
|
|
|
2d44415 |
return false;
|
|
|
2d44415 |
@@ -1198,29 +1182,9 @@ bool QProcessPrivate::waitForFinished(int msecs)
|
|
|
2d44415 |
stopWatch.start();
|
|
|
2d44415 |
|
|
|
2d44415 |
forever {
|
|
|
2d44415 |
- fd_set fdread;
|
|
|
2d44415 |
- fd_set fdwrite;
|
|
|
2d44415 |
- int nfds = -1;
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- FD_ZERO(&fdread);
|
|
|
2d44415 |
- FD_ZERO(&fdwrite);
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- if (processState == QProcess::Starting)
|
|
|
2d44415 |
- add_fd(nfds, childStartedPipe[0], &fdread);
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- if (stdoutChannel.pipe[0] != -1)
|
|
|
2d44415 |
- add_fd(nfds, stdoutChannel.pipe[0], &fdread);
|
|
|
2d44415 |
- if (stderrChannel.pipe[0] != -1)
|
|
|
2d44415 |
- add_fd(nfds, stderrChannel.pipe[0], &fdread);
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- if (processState == QProcess::Running)
|
|
|
2d44415 |
- add_fd(nfds, deathPipe[0], &fdread);
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1)
|
|
|
2d44415 |
- add_fd(nfds, stdinChannel.pipe[1], &fdwrite);
|
|
|
2d44415 |
-
|
|
|
2d44415 |
+ QProcessFDSet fdset(*this);
|
|
|
2d44415 |
int timeout = qt_timeout_value(msecs, stopWatch.elapsed());
|
|
|
2d44415 |
- int ret = select_msecs(nfds + 1, &fdread, &fdwrite, timeout);
|
|
|
2d44415 |
+ int ret = fdset.poll(timeout);
|
|
|
2d44415 |
if (ret < 0) {
|
|
|
2d44415 |
break;
|
|
|
2d44415 |
}
|
|
|
2d44415 |
@@ -1230,20 +1194,20 @@ bool QProcessPrivate::waitForFinished(int msecs)
|
|
|
2d44415 |
return false;
|
|
|
2d44415 |
}
|
|
|
2d44415 |
|
|
|
2d44415 |
- if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) {
|
|
|
2d44415 |
+ if (qt_readable(fdset.started())) {
|
|
|
2d44415 |
if (!_q_startupNotification())
|
|
|
2d44415 |
return false;
|
|
|
2d44415 |
}
|
|
|
2d44415 |
- if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
|
|
|
2d44415 |
+ if (qt_writable(fdset.stdin()))
|
|
|
2d44415 |
_q_canWrite();
|
|
|
2d44415 |
|
|
|
2d44415 |
- if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread))
|
|
|
2d44415 |
+ if (qt_readable(fdset.stdout()))
|
|
|
2d44415 |
_q_canReadStandardOutput();
|
|
|
2d44415 |
|
|
|
2d44415 |
- if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread))
|
|
|
2d44415 |
+ if (qt_readable(fdset.stderr()))
|
|
|
2d44415 |
_q_canReadStandardError();
|
|
|
2d44415 |
|
|
|
2d44415 |
- if (deathPipe[0] == -1 || FD_ISSET(deathPipe[0], &fdread)) {
|
|
|
2d44415 |
+ if (qt_readable(fdset.death())) {
|
|
|
2d44415 |
if (_q_processDied())
|
|
|
2d44415 |
return true;
|
|
|
2d44415 |
}
|
|
|
2d44415 |
@@ -1253,10 +1217,10 @@ bool QProcessPrivate::waitForFinished(int msecs)
|
|
|
2d44415 |
|
|
|
2d44415 |
bool QProcessPrivate::waitForWrite(int msecs)
|
|
|
2d44415 |
{
|
|
|
2d44415 |
- fd_set fdwrite;
|
|
|
2d44415 |
- FD_ZERO(&fdwrite);
|
|
|
2d44415 |
- FD_SET(stdinChannel.pipe[1], &fdwrite);
|
|
|
2d44415 |
- return select_msecs(stdinChannel.pipe[1] + 1, 0, &fdwrite, msecs < 0 ? 0 : msecs) == 1;
|
|
|
2d44415 |
+ pollfd fd;
|
|
|
2d44415 |
+ fd.fd = stdinChannel.pipe[1];
|
|
|
2d44415 |
+ fd.events = POLLIN;
|
|
|
2d44415 |
+ return qt_safe_poll(&fd, 1, msecs);
|
|
|
2d44415 |
}
|
|
|
2d44415 |
|
|
|
2d44415 |
void QProcessPrivate::findExitCode()
|
|
|
2d44415 |
diff --git a/src/corelib/kernel/qcore_unix.cpp b/src/corelib/kernel/qcore_unix.cpp
|
|
|
2d44415 |
index cc54798..ca178bb 100644
|
|
|
2d44415 |
--- a/src/corelib/kernel/qcore_unix.cpp
|
|
|
2d44415 |
+++ b/src/corelib/kernel/qcore_unix.cpp
|
|
|
2d44415 |
@@ -103,4 +103,165 @@ int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept,
|
|
|
2d44415 |
}
|
|
|
2d44415 |
}
|
|
|
2d44415 |
|
|
|
2d44415 |
+#ifndef Q_OS_VXWORKS
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+int qt_safe_poll(struct pollfd *fds, int nfds, int timeout_ms, bool retry_eintr)
|
|
|
2d44415 |
+{
|
|
|
2d44415 |
+ if (nfds == 0)
|
|
|
2d44415 |
+ return 0;
|
|
|
2d44415 |
+ if (nfds < 0) {
|
|
|
2d44415 |
+ errno = EINVAL;
|
|
|
2d44415 |
+ return -1;
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+ // Retry on ret == 0 if the deadline has not yet passed because
|
|
|
2d44415 |
+ // Linux can return early from the syscall, without setting EINTR.
|
|
|
2d44415 |
+ if (timeout_ms < 0) {
|
|
|
2d44415 |
+ forever {
|
|
|
2d44415 |
+ int ret = ::poll(fds, nfds, -1);
|
|
|
2d44415 |
+ if (ret > 0)
|
|
|
2d44415 |
+ return ret;
|
|
|
2d44415 |
+ if (retry_eintr) {
|
|
|
2d44415 |
+ if (ret == 0 || ret == -1 && errno == EINTR) {
|
|
|
2d44415 |
+ continue;
|
|
|
2d44415 |
+ } else {
|
|
|
2d44415 |
+ return -1;
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+ if (ret == 0) {
|
|
|
2d44415 |
+ errno = EINTR;
|
|
|
2d44415 |
+ return -1;
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+ return ret;
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+ timeval previous = qt_gettime();
|
|
|
2d44415 |
+ timeval deadline = previous;
|
|
|
2d44415 |
+ deadline.tv_sec += timeout_ms / 1000;
|
|
|
2d44415 |
+ deadline.tv_usec += (timeout_ms % 1000) * 1000;
|
|
|
2d44415 |
+ if (deadline.tv_usec >= 1000000) {
|
|
|
2d44415 |
+ ++deadline.tv_sec;
|
|
|
2d44415 |
+ deadline.tv_usec -= 1000000;
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+ int remaining = timeout_ms;
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+ forever {
|
|
|
2d44415 |
+ int ret = ::poll(fds, nfds, remaining);
|
|
|
2d44415 |
+ if (ret > 0)
|
|
|
2d44415 |
+ return ret;
|
|
|
2d44415 |
+ timeval now = qt_gettime();
|
|
|
2d44415 |
+ if ((now.tv_sec > deadline.tv_sec // past deadline
|
|
|
2d44415 |
+ || (now.tv_sec == deadline.tv_sec
|
|
|
2d44415 |
+ && now.tv_usec >= deadline.tv_usec))
|
|
|
2d44415 |
+ || (now.tv_sec < previous.tv_sec // time warp
|
|
|
2d44415 |
+ || (now.tv_sec == previous.tv_sec
|
|
|
2d44415 |
+ && now.tv_usec < previous.tv_usec))
|
|
|
2d44415 |
+ || (ret < 0 && (errno != EINTR || !retry_eintr))) // other error
|
|
|
2d44415 |
+ return ret;
|
|
|
2d44415 |
+ if (ret == 0 && !retry_eintr) {
|
|
|
2d44415 |
+ errno = EINTR;
|
|
|
2d44415 |
+ return -1;
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+ remaining = (deadline.tv_sec - now.tv_sec) * 1000
|
|
|
2d44415 |
+ + (deadline.tv_usec - now.tv_usec) / 1000;
|
|
|
2d44415 |
+ previous = now;
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+}
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+#else
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+// Poll emulation for VxWorks.
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+static int mark_bad_descriptors(pollfd *fds, int nfds)
|
|
|
2d44415 |
+{
|
|
|
2d44415 |
+ fd_set r;
|
|
|
2d44415 |
+ FD_ZERO(&r);
|
|
|
2d44415 |
+ struct timeval tv;
|
|
|
2d44415 |
+ tv.tv_sec = 0;
|
|
|
2d44415 |
+ tv.tv_usec = 0;
|
|
|
2d44415 |
+ int ret = 0;
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+ // Check each descriptor invidually for badness.
|
|
|
2d44415 |
+ for (int i = 0; i < nfds; ++i) {
|
|
|
2d44415 |
+ pollfd &fd(fds[i]);
|
|
|
2d44415 |
+ if (fd.fd >= 0) {
|
|
|
2d44415 |
+ FD_SET(fd.fd, &r);
|
|
|
2d44415 |
+ int ret = qt_safe_select(fd.fd + 1, &r, NULL, NULL, &tv;;
|
|
|
2d44415 |
+ FD_CLR(fd.fd, &r);
|
|
|
2d44415 |
+ if (ret < 0 && errno == EBADF) {
|
|
|
2d44415 |
+ fd.revents = POLLNVAL;
|
|
|
2d44415 |
+ ++ret;
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+ Q_ASSERT(ret > 0);
|
|
|
2d44415 |
+ return ret;
|
|
|
2d44415 |
+}
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+int qt_safe_poll(pollfd *fds, int nfds, int timeout, bool retry_eintr)
|
|
|
2d44415 |
+{
|
|
|
2d44415 |
+ fd_set r, w;
|
|
|
2d44415 |
+ FD_ZERO(&r);
|
|
|
2d44415 |
+ FD_ZERO(&w);
|
|
|
2d44415 |
+ int maxfd = -1;
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+ // Extract the watched descriptors.
|
|
|
2d44415 |
+ for (int i = 0; i < nfds; ++i) {
|
|
|
2d44415 |
+ pollfd &fd(fds[i]);
|
|
|
2d44415 |
+ if (fd.fd >= 0 && fd.fd < FD_SETSIZE) {
|
|
|
2d44415 |
+ if (fd.events & POLLIN) {
|
|
|
2d44415 |
+ FD_SET(fd.fd, &r);
|
|
|
2d44415 |
+ if (fd.fd > maxfd)
|
|
|
2d44415 |
+ maxfd = fd.fd;
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+ if (fd.events & POLLOUT) {
|
|
|
2d44415 |
+ FD_SET(fd.fd, &w);
|
|
|
2d44415 |
+ if (fd.fd > maxfd)
|
|
|
2d44415 |
+ maxfd = fd.fd;
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+ // If timeout is negative, wait indefinitely for activity.
|
|
|
2d44415 |
+ timeval tv;
|
|
|
2d44415 |
+ timeval *ptv;
|
|
|
2d44415 |
+ if (timeout >= 0) {
|
|
|
2d44415 |
+ tv.tv_sec = timeout / 1000;
|
|
|
2d44415 |
+ tv.tv_usec = (timeout % 1000) * 1000;
|
|
|
2d44415 |
+ ptv = &tv;
|
|
|
2d44415 |
+ } else
|
|
|
2d44415 |
+ ptv = NULL;
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+ int ret;
|
|
|
2d44415 |
+ if (retry_eintr)
|
|
|
2d44415 |
+ ret = qt_safe_select(maxfd + 1, &r, &w, NULL, ptv);
|
|
|
2d44415 |
+ else
|
|
|
2d44415 |
+ ret = ::select(maxfd + 1, &r, &w, NULL, ptv);
|
|
|
2d44415 |
+ if (ret < 0 && errno == EBADF) {
|
|
|
2d44415 |
+ return mark_bad_descriptors(fds, nfds);
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+ if (ret <= 0)
|
|
|
2d44415 |
+ return ret;
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+ // Set the revents flags.
|
|
|
2d44415 |
+ ret = 0;
|
|
|
2d44415 |
+ for (int i = 0; i < nfds; ++i) {
|
|
|
2d44415 |
+ pollfd &fd(fds[i]);
|
|
|
2d44415 |
+ fd.revents = 0;
|
|
|
2d44415 |
+ if (fd.fd >= 0 && fd.fd < FD_SETSIZE) {
|
|
|
2d44415 |
+ if ((fd.events & POLLIN) && FD_ISSET(fd.fd, &r))
|
|
|
2d44415 |
+ fd.revents |= POLLIN;
|
|
|
2d44415 |
+ if ((fd.events & POLLOUT) && FD_ISSET(fd.fd, &w))
|
|
|
2d44415 |
+ fd.revents |= POLLOUT;
|
|
|
2d44415 |
+ if (fd.revents)
|
|
|
2d44415 |
+ ++ret;
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+ Q_ASSERT(ret > 0);
|
|
|
2d44415 |
+ return ret;
|
|
|
2d44415 |
+}
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+#endif // Q_OS_VXWORKS
|
|
|
2d44415 |
+
|
|
|
2d44415 |
QT_END_NAMESPACE
|
|
|
2d44415 |
diff --git a/src/corelib/kernel/qcore_unix_p.h b/src/corelib/kernel/qcore_unix_p.h
|
|
|
2d44415 |
index 6342b03..f7f4767 100644
|
|
|
2d44415 |
--- a/src/corelib/kernel/qcore_unix_p.h
|
|
|
2d44415 |
+++ b/src/corelib/kernel/qcore_unix_p.h
|
|
|
2d44415 |
@@ -71,6 +71,8 @@
|
|
|
2d44415 |
|
|
|
2d44415 |
#if defined(Q_OS_VXWORKS)
|
|
|
2d44415 |
# include <ioLib.h>
|
|
|
2d44415 |
+#else
|
|
|
2d44415 |
+# include <poll.h>
|
|
|
2d44415 |
#endif
|
|
|
2d44415 |
|
|
|
2d44415 |
struct sockaddr;
|
|
|
2d44415 |
@@ -341,6 +343,36 @@ void qt_nanosleep(timespec amount);
|
|
|
2d44415 |
Q_CORE_EXPORT int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept,
|
|
|
2d44415 |
const struct timeval *tv);
|
|
|
2d44415 |
|
|
|
2d44415 |
+#ifdef Q_OS_VXWORKS
|
|
|
2d44415 |
+// Poll emulation for VxWorks. Provided by <poll.h> on other systems.
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+struct pollfd {
|
|
|
2d44415 |
+ int fd;
|
|
|
2d44415 |
+ short events;
|
|
|
2d44415 |
+ short revents;
|
|
|
2d44415 |
+};
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+#define POLLIN 1
|
|
|
2d44415 |
+#define POLLOUT 2
|
|
|
2d44415 |
+#define POLLERR 4
|
|
|
2d44415 |
+#define POLLHUP 8
|
|
|
2d44415 |
+#define POLLNVAL 16
|
|
|
2d44415 |
+#endif
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+inline bool qt_readable(const pollfd &fd)
|
|
|
2d44415 |
+{
|
|
|
2d44415 |
+ return fd.fd >= 0 && (fd.revents & (POLLIN | POLLHUP | POLLERR | POLLNVAL)) != 0;
|
|
|
2d44415 |
+}
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+inline bool qt_writable(const pollfd &fd)
|
|
|
2d44415 |
+{
|
|
|
2d44415 |
+ return fd.fd >= 0 && (fd.revents & (POLLOUT | POLLHUP | POLLERR | POLLNVAL)) != 0;
|
|
|
2d44415 |
+}
|
|
|
2d44415 |
+
|
|
|
2d44415 |
+// Deprecated due to FD_SETSIZE limitation, use qt_safe_poll instead.
|
|
|
2d44415 |
+Q_CORE_EXPORT int qt_safe_poll(pollfd *fds, int nfds, int timeout,
|
|
|
2d44415 |
+ bool retry_eintr = true);
|
|
|
2d44415 |
+
|
|
|
2d44415 |
// according to X/OPEN we have to define semun ourselves
|
|
|
2d44415 |
// we use prefix as on some systems sem.h will have it
|
|
|
2d44415 |
struct semid_ds;
|
|
|
2d44415 |
diff --git a/src/network/socket/qlocalserver_unix.cpp b/src/network/socket/qlocalserver_unix.cpp
|
|
|
2d44415 |
index 2bcf1ac..efb8128 100644
|
|
|
2d44415 |
--- a/src/network/socket/qlocalserver_unix.cpp
|
|
|
2d44415 |
+++ b/src/network/socket/qlocalserver_unix.cpp
|
|
|
2d44415 |
@@ -293,16 +293,11 @@ void QLocalServerPrivate::_q_onNewConnection()
|
|
|
2d44415 |
|
|
|
2d44415 |
void QLocalServerPrivate::waitForNewConnection(int msec, bool *timedOut)
|
|
|
2d44415 |
{
|
|
|
2d44415 |
- fd_set readfds;
|
|
|
2d44415 |
- FD_ZERO(&readfds);
|
|
|
2d44415 |
- FD_SET(listenSocket, &readfds);
|
|
|
2d44415 |
+ struct pollfd fd;
|
|
|
2d44415 |
+ fd.fd = listenSocket;
|
|
|
2d44415 |
+ fd.events = POLLIN;
|
|
|
2d44415 |
|
|
|
2d44415 |
- timeval timeout;
|
|
|
2d44415 |
- timeout.tv_sec = msec / 1000;
|
|
|
2d44415 |
- timeout.tv_usec = (msec % 1000) * 1000;
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- int result = -1;
|
|
|
2d44415 |
- result = qt_safe_select(listenSocket + 1, &readfds, 0, 0, (msec == -1) ? 0 : &timeout);
|
|
|
2d44415 |
+ int result = qt_safe_poll(&fd, 1, msec);
|
|
|
2d44415 |
if (-1 == result) {
|
|
|
2d44415 |
setError(QLatin1String("QLocalServer::waitForNewConnection"));
|
|
|
2d44415 |
closeServer();
|
|
|
2d44415 |
diff --git a/src/network/socket/qlocalsocket_unix.cpp b/src/network/socket/qlocalsocket_unix.cpp
|
|
|
2d44415 |
index 49eb71a..c598c2b 100644
|
|
|
2d44415 |
--- a/src/network/socket/qlocalsocket_unix.cpp
|
|
|
2d44415 |
+++ b/src/network/socket/qlocalsocket_unix.cpp
|
|
|
2d44415 |
@@ -56,10 +56,6 @@
|
|
|
2d44415 |
#include <qdebug.h>
|
|
|
2d44415 |
#include <qelapsedtimer.h>
|
|
|
2d44415 |
|
|
|
2d44415 |
-#ifdef Q_OS_VXWORKS
|
|
|
2d44415 |
-# include <selectLib.h>
|
|
|
2d44415 |
-#endif
|
|
|
2d44415 |
-
|
|
|
2d44415 |
#define QT_CONNECT_TIMEOUT 30000
|
|
|
2d44415 |
|
|
|
2d44415 |
QT_BEGIN_NAMESPACE
|
|
|
2d44415 |
@@ -524,25 +520,16 @@ bool QLocalSocket::waitForConnected(int msec)
|
|
|
2d44415 |
if (state() != ConnectingState)
|
|
|
2d44415 |
return (state() == ConnectedState);
|
|
|
2d44415 |
|
|
|
2d44415 |
- fd_set fds;
|
|
|
2d44415 |
- FD_ZERO(&fds);
|
|
|
2d44415 |
- FD_SET(d->connectingSocket, &fds);
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- timeval timeout;
|
|
|
2d44415 |
- timeout.tv_sec = msec / 1000;
|
|
|
2d44415 |
- timeout.tv_usec = (msec % 1000) * 1000;
|
|
|
2d44415 |
+ pollfd fd;
|
|
|
2d44415 |
+ fd.fd = d->connectingSocket;
|
|
|
2d44415 |
+ fd.events = POLLIN | POLLOUT;
|
|
|
2d44415 |
|
|
|
2d44415 |
- // timeout can not be 0 or else select will return an error.
|
|
|
2d44415 |
- if (0 == msec)
|
|
|
2d44415 |
- timeout.tv_usec = 1000;
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- int result = -1;
|
|
|
2d44415 |
- // on Linux timeout will be updated by select, but _not_ on other systems.
|
|
|
2d44415 |
+ int result;
|
|
|
2d44415 |
QElapsedTimer timer;
|
|
|
2d44415 |
+ int remaining = msec > 0 ? msec : 1000;
|
|
|
2d44415 |
timer.start();
|
|
|
2d44415 |
- while (state() == ConnectingState
|
|
|
2d44415 |
- && (-1 == msec || timer.elapsed() < msec)) {
|
|
|
2d44415 |
- result = ::select(d->connectingSocket + 1, &fds, 0, 0, &timeout);
|
|
|
2d44415 |
+ while (state() == ConnectingState) {
|
|
|
2d44415 |
+ result = qt_safe_poll(&fd, 1, remaining, /* retry_eintr */ false);
|
|
|
2d44415 |
if (-1 == result && errno != EINTR) {
|
|
|
2d44415 |
d->errorOccurred( QLocalSocket::UnknownSocketError,
|
|
|
2d44415 |
QLatin1String("QLocalSocket::waitForConnected"));
|
|
|
2d44415 |
@@ -550,6 +537,11 @@ bool QLocalSocket::waitForConnected(int msec)
|
|
|
2d44415 |
}
|
|
|
2d44415 |
if (result > 0)
|
|
|
2d44415 |
d->_q_connectToSocket();
|
|
|
2d44415 |
+ if (msec >= 0) {
|
|
|
2d44415 |
+ remaining = timer.elapsed() - msec;
|
|
|
2d44415 |
+ if (remaining < 0)
|
|
|
2d44415 |
+ break;
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
}
|
|
|
2d44415 |
|
|
|
2d44415 |
return (state() == ConnectedState);
|
|
|
2d44415 |
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp
|
|
|
2d44415 |
index 4f3408b..a1bb298 100644
|
|
|
2d44415 |
--- a/src/network/socket/qnativesocketengine_unix.cpp
|
|
|
2d44415 |
+++ b/src/network/socket/qnativesocketengine_unix.cpp
|
|
|
2d44415 |
@@ -1122,48 +1122,40 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize)
|
|
|
2d44415 |
|
|
|
2d44415 |
int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const
|
|
|
2d44415 |
{
|
|
|
2d44415 |
- fd_set fds;
|
|
|
2d44415 |
- FD_ZERO(&fds);
|
|
|
2d44415 |
- FD_SET(socketDescriptor, &fds);
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- struct timeval tv;
|
|
|
2d44415 |
- tv.tv_sec = timeout / 1000;
|
|
|
2d44415 |
- tv.tv_usec = (timeout % 1000) * 1000;
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- int retval;
|
|
|
2d44415 |
- if (selectForRead)
|
|
|
2d44415 |
- retval = qt_safe_select(socketDescriptor + 1, &fds, 0, 0, timeout < 0 ? 0 : &tv;;
|
|
|
2d44415 |
- else
|
|
|
2d44415 |
- retval = qt_safe_select(socketDescriptor + 1, 0, &fds, 0, timeout < 0 ? 0 : &tv;;
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- return retval;
|
|
|
2d44415 |
+ struct pollfd fd;
|
|
|
2d44415 |
+ fd.fd = socketDescriptor;
|
|
|
2d44415 |
+ if (selectForRead) {
|
|
|
2d44415 |
+ fd.events = POLLIN;
|
|
|
2d44415 |
+ } else {
|
|
|
2d44415 |
+ fd.events = POLLOUT;
|
|
|
2d44415 |
+ }
|
|
|
2d44415 |
+ return qt_safe_poll(&fd, 1, timeout);
|
|
|
2d44415 |
}
|
|
|
2d44415 |
|
|
|
2d44415 |
int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite,
|
|
|
2d44415 |
bool *selectForRead, bool *selectForWrite) const
|
|
|
2d44415 |
{
|
|
|
2d44415 |
- fd_set fdread;
|
|
|
2d44415 |
- FD_ZERO(&fdread);
|
|
|
2d44415 |
+ struct pollfd fd;
|
|
|
2d44415 |
+ fd.fd = socketDescriptor;
|
|
|
2d44415 |
if (checkRead)
|
|
|
2d44415 |
- FD_SET(socketDescriptor, &fdread);
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- fd_set fdwrite;
|
|
|
2d44415 |
- FD_ZERO(&fdwrite);
|
|
|
2d44415 |
+ fd.events = POLLIN;
|
|
|
2d44415 |
+ else
|
|
|
2d44415 |
+ fd.events = 0;
|
|
|
2d44415 |
if (checkWrite)
|
|
|
2d44415 |
- FD_SET(socketDescriptor, &fdwrite);
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- struct timeval tv;
|
|
|
2d44415 |
- tv.tv_sec = timeout / 1000;
|
|
|
2d44415 |
- tv.tv_usec = (timeout % 1000) * 1000;
|
|
|
2d44415 |
-
|
|
|
2d44415 |
- int ret;
|
|
|
2d44415 |
- ret = qt_safe_select(socketDescriptor + 1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv;;
|
|
|
2d44415 |
-
|
|
|
2d44415 |
+ fd.events |= POLLOUT;
|
|
|
2d44415 |
+ int ret = qt_safe_poll(&fd, 1, timeout);
|
|
|
2d44415 |
if (ret <= 0)
|
|
|
2d44415 |
- return ret;
|
|
|
2d44415 |
- *selectForRead = FD_ISSET(socketDescriptor, &fdread);
|
|
|
2d44415 |
- *selectForWrite = FD_ISSET(socketDescriptor, &fdwrite);
|
|
|
2d44415 |
-
|
|
|
2d44415 |
+ return ret;
|
|
|
2d44415 |
+ bool r = (fd.revents & (POLLIN | POLLHUP | POLLERR)) != 0;
|
|
|
2d44415 |
+ bool w = (fd.revents & (POLLOUT | POLLHUP | POLLERR)) != 0;
|
|
|
2d44415 |
+ // Emulate the return value from select(2).
|
|
|
2d44415 |
+ ret = 0;
|
|
|
2d44415 |
+ if (r)
|
|
|
2d44415 |
+ ++ret;
|
|
|
2d44415 |
+ if (w)
|
|
|
2d44415 |
+ ++ret;
|
|
|
2d44415 |
+ *selectForRead = r;
|
|
|
2d44415 |
+ *selectForWrite = w;
|
|
|
2d44415 |
return ret;
|
|
|
2d44415 |
}
|
|
|
2d44415 |
|