1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-07-18 19:41:01 -05:00

Switch to using poll(2) in place of select(2).

I've always thought poll was more hassle to set up, because if you
want to reuse part of your pollfds list between calls then you have to
index every fd by its position in the list as well as the fd number
itself, which gives you twice as many indices to keep track of than if
the fd is always its own key.

But the problem is that select is fundamentally limited to the range
of fds that can fit in an fd_set, which is not the range of fds that
can _exist_, so I've had a change of heart and now have to go with
poll.

For the moment, I've surrounded it with a 'pollwrapper' structure that
lets me treat it more or less like select, containing a tree234 that
maps each fd to its location in the list, and also translating between
the simple select r/w/x classification and the richer poll flags.
That's let me do the migration with minimal disruption to the call
sites.

In future perhaps I can start using poll more directly, and/or using
the richer flag system (though the latter might be fiddly because of
sometimes being constrained to use the glib event loop). But this will
do for now.
This commit is contained in:
Simon Tatham
2019-02-07 18:21:06 +00:00
parent 47202c4e16
commit 5c926d9ea4
13 changed files with 272 additions and 148 deletions

View File

@ -13,9 +13,6 @@
#include <errno.h>
#include <assert.h>
#include <glob.h>
#ifndef HAVE_NO_SYS_SELECT_H
#include <sys/select.h>
#endif
#include "putty.h"
#include "ssh.h"
@ -448,10 +445,9 @@ char *dir_file_cat(const char *dir, const char *file)
*/
static int ssh_sftp_do_select(bool include_stdin, bool no_fds_ok)
{
fd_set rset, wset, xset;
int i, *fdlist;
size_t fdsize;
int fd, fdcount, fdstate, rwx, ret, maxfd;
int fd, fdcount, fdstate, rwx, ret;
unsigned long now = GETTICKCOUNT();
unsigned long next;
bool done_something = false;
@ -459,6 +455,8 @@ static int ssh_sftp_do_select(bool include_stdin, bool no_fds_ok)
fdlist = NULL;
fdsize = 0;
pollwrapper *pw = pollwrap_new();
do {
/* Count the currently active fds. */
@ -472,10 +470,7 @@ static int ssh_sftp_do_select(bool include_stdin, bool no_fds_ok)
/* Expand the fdlist buffer if necessary. */
sgrowarray(fdlist, fdsize, i);
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_ZERO(&xset);
maxfd = 0;
pollwrap_clear(pw);
/*
* Add all currently open fds to the select sets, and store
@ -485,29 +480,20 @@ static int ssh_sftp_do_select(bool include_stdin, bool no_fds_ok)
for (fd = first_fd(&fdstate, &rwx); fd >= 0;
fd = next_fd(&fdstate, &rwx)) {
fdlist[fdcount++] = fd;
if (rwx & 1)
FD_SET_MAX(fd, maxfd, rset);
if (rwx & 2)
FD_SET_MAX(fd, maxfd, wset);
if (rwx & 4)
FD_SET_MAX(fd, maxfd, xset);
pollwrap_add_fd_rwx(pw, fd, rwx);
}
if (include_stdin)
FD_SET_MAX(0, maxfd, rset);
pollwrap_add_fd_rwx(pw, 0, SELECT_R);
if (toplevel_callback_pending()) {
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
ret = select(maxfd, &rset, &wset, &xset, &tv);
ret = pollwrap_poll_instant(pw);
if (ret == 0)
done_something |= run_toplevel_callbacks();
} else if (run_timers(now, &next)) {
do {
unsigned long then;
long ticks;
struct timeval tv;
then = now;
now = GETTICKCOUNT();
@ -515,38 +501,44 @@ static int ssh_sftp_do_select(bool include_stdin, bool no_fds_ok)
ticks = 0;
else
ticks = next - now;
tv.tv_sec = ticks / 1000;
tv.tv_usec = ticks % 1000 * 1000;
ret = select(maxfd, &rset, &wset, &xset, &tv);
if (ret == 0)
bool overflow = false;
if (ticks > INT_MAX) {
ticks = INT_MAX;
overflow = true;
}
ret = pollwrap_poll_timeout(pw, ticks);
if (ret == 0 && !overflow)
now = next;
else
now = GETTICKCOUNT();
} while (ret < 0 && errno == EINTR);
} else {
do {
ret = select(maxfd, &rset, &wset, &xset, NULL);
ret = pollwrap_poll_endless(pw);
} while (ret < 0 && errno == EINTR);
}
} while (ret == 0 && !done_something);
if (ret < 0) {
perror("select");
perror("poll");
exit(1);
}
for (i = 0; i < fdcount; i++) {
fd = fdlist[i];
int rwx = pollwrap_get_fd_rwx(pw, fd);
/*
* We must process exceptional notifications before
* ordinary readability ones, or we may go straight
* past the urgent marker.
*/
if (FD_ISSET(fd, &xset))
if (rwx & SELECT_X)
select_result(fd, SELECT_X);
if (FD_ISSET(fd, &rset))
if (rwx & SELECT_R)
select_result(fd, SELECT_R);
if (FD_ISSET(fd, &wset))
if (rwx & SELECT_W)
select_result(fd, SELECT_W);
}
@ -554,7 +546,9 @@ static int ssh_sftp_do_select(bool include_stdin, bool no_fds_ok)
run_toplevel_callbacks();
return FD_ISSET(0, &rset) ? 1 : 0;
int toret = pollwrap_check_fd_rwx(pw, 0, SELECT_R) ? 1 : 0;
pollwrap_free(pw);
return toret;
}
/*