mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-07-03 04:22:47 -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:
@ -14,9 +14,6 @@
|
||||
#include <pwd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/time.h>
|
||||
#ifndef HAVE_NO_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
#define PUTTY_DO_GLOBALS /* actually _define_ globals */
|
||||
#include "putty.h"
|
||||
@ -873,36 +870,33 @@ int main(int argc, char **argv)
|
||||
sending = false;
|
||||
now = GETTICKCOUNT();
|
||||
|
||||
pollwrapper *pw = pollwrap_new();
|
||||
|
||||
while (1) {
|
||||
fd_set rset, wset, xset;
|
||||
int maxfd;
|
||||
int rwx;
|
||||
int ret;
|
||||
unsigned long next;
|
||||
|
||||
FD_ZERO(&rset);
|
||||
FD_ZERO(&wset);
|
||||
FD_ZERO(&xset);
|
||||
maxfd = 0;
|
||||
pollwrap_clear(pw);
|
||||
|
||||
FD_SET_MAX(signalpipe[0], maxfd, rset);
|
||||
pollwrap_add_fd_rwx(pw, signalpipe[0], SELECT_R);
|
||||
|
||||
if (!sending &&
|
||||
backend_connected(backend) &&
|
||||
backend_sendok(backend) &&
|
||||
backend_sendbuffer(backend) < MAX_STDIN_BACKLOG) {
|
||||
/* If we're OK to send, then try to read from stdin. */
|
||||
FD_SET_MAX(STDIN_FILENO, maxfd, rset);
|
||||
pollwrap_add_fd_rwx(pw, STDIN_FILENO, SELECT_R);
|
||||
}
|
||||
|
||||
if (bufchain_size(&stdout_data) > 0) {
|
||||
/* If we have data for stdout, try to write to stdout. */
|
||||
FD_SET_MAX(STDOUT_FILENO, maxfd, wset);
|
||||
pollwrap_add_fd_rwx(pw, STDOUT_FILENO, SELECT_W);
|
||||
}
|
||||
|
||||
if (bufchain_size(&stderr_data) > 0) {
|
||||
/* If we have data for stderr, try to write to stderr. */
|
||||
FD_SET_MAX(STDERR_FILENO, maxfd, wset);
|
||||
pollwrap_add_fd_rwx(pw, STDERR_FILENO, SELECT_W);
|
||||
}
|
||||
|
||||
/* Count the currently active fds. */
|
||||
@ -914,31 +908,22 @@ int main(int argc, char **argv)
|
||||
sgrowarray(fdlist, fdsize, i);
|
||||
|
||||
/*
|
||||
* Add all currently open fds to the select sets, and store
|
||||
* them in fdlist as well.
|
||||
* Add all currently open fds to pw, and store them in fdlist
|
||||
* as well.
|
||||
*/
|
||||
int fdcount = 0;
|
||||
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 (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);
|
||||
} else if (run_timers(now, &next)) {
|
||||
do {
|
||||
unsigned long then;
|
||||
long ticks;
|
||||
struct timeval tv;
|
||||
|
||||
then = now;
|
||||
now = GETTICKCOUNT();
|
||||
@ -946,42 +931,48 @@ int main(int argc, char **argv)
|
||||
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 {
|
||||
ret = select(maxfd, &rset, &wset, &xset, NULL);
|
||||
ret = pollwrap_poll_endless(pw);
|
||||
}
|
||||
|
||||
if (ret < 0 && errno == EINTR)
|
||||
continue;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (FD_ISSET(signalpipe[0], &rset)) {
|
||||
if (pollwrap_check_fd_rwx(pw, signalpipe[0], SELECT_R)) {
|
||||
char c[1];
|
||||
struct winsize size;
|
||||
if (read(signalpipe[0], c, 1) <= 0)
|
||||
@ -991,7 +982,7 @@ int main(int argc, char **argv)
|
||||
backend_size(backend, size.ws_col, size.ws_row);
|
||||
}
|
||||
|
||||
if (FD_ISSET(STDIN_FILENO, &rset)) {
|
||||
if (pollwrap_check_fd_rwx(pw, STDIN_FILENO, SELECT_R)) {
|
||||
char buf[4096];
|
||||
int ret;
|
||||
|
||||
@ -1013,11 +1004,11 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (FD_ISSET(STDOUT_FILENO, &wset)) {
|
||||
if (pollwrap_check_fd_rwx(pw, STDOUT_FILENO, SELECT_W)) {
|
||||
backend_unthrottle(backend, try_output(false));
|
||||
}
|
||||
|
||||
if (FD_ISSET(STDERR_FILENO, &wset)) {
|
||||
if (pollwrap_check_fd_rwx(pw, STDERR_FILENO, SELECT_W)) {
|
||||
backend_unthrottle(backend, try_output(true));
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user