1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-10 01:48:00 +00:00
putty-source/unix/uxpoll.c
Simon Tatham 5c926d9ea4 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.
2019-03-16 12:25:23 +00:00

137 lines
3.0 KiB
C

#include <poll.h>
#include "putty.h"
#include "tree234.h"
struct pollwrapper {
struct pollfd *fds;
size_t nfd, fdsize;
tree234 *fdtopos;
};
typedef struct pollwrap_fdtopos pollwrap_fdtopos;
struct pollwrap_fdtopos {
int fd;
size_t pos;
};
static int pollwrap_fd_cmp(void *av, void *bv)
{
pollwrap_fdtopos *a = (pollwrap_fdtopos *)av;
pollwrap_fdtopos *b = (pollwrap_fdtopos *)bv;
return a->fd < b->fd ? -1 : a->fd > b->fd ? +1 : 0;
}
pollwrapper *pollwrap_new(void)
{
pollwrapper *pw = snew(pollwrapper);
pw->fdsize = 16;
pw->nfd = 0;
pw->fds = snewn(pw->fdsize, struct pollfd);
pw->fdtopos = newtree234(pollwrap_fd_cmp);
return pw;
}
void pollwrap_free(pollwrapper *pw)
{
pollwrap_clear(pw);
freetree234(pw->fdtopos);
sfree(pw->fds);
sfree(pw);
}
void pollwrap_clear(pollwrapper *pw)
{
pw->nfd = 0;
for (pollwrap_fdtopos *f2p;
(f2p = delpos234(pw->fdtopos, 0)) != NULL ;)
sfree(f2p);
}
void pollwrap_add_fd_events(pollwrapper *pw, int fd, int events)
{
pollwrap_fdtopos *f2p, f2p_find;
assert(fd >= 0);
f2p_find.fd = fd;
f2p = find234(pw->fdtopos, &f2p_find, NULL);
if (!f2p) {
sgrowarray(pw->fds, pw->fdsize, pw->nfd);
size_t index = pw->nfd++;
pw->fds[index].fd = fd;
pw->fds[index].events = pw->fds[index].revents = 0;
f2p = snew(pollwrap_fdtopos);
f2p->fd = fd;
f2p->pos = index;
pollwrap_fdtopos *added = add234(pw->fdtopos, f2p);
assert(added == f2p);
}
pw->fds[f2p->pos].events |= events;
}
#define SELECT_R_IN (POLLIN | POLLRDNORM | POLLRDBAND)
#define SELECT_W_IN (POLLOUT | POLLWRNORM | POLLWRBAND)
#define SELECT_X_IN (POLLPRI)
#define SELECT_R_OUT (SELECT_R_IN | POLLERR | POLLHUP)
#define SELECT_W_OUT (SELECT_W_IN | POLLERR)
#define SELECT_X_OUT (SELECT_X_IN)
void pollwrap_add_fd_rwx(pollwrapper *pw, int fd, int rwx)
{
int events = 0;
if (rwx & SELECT_R)
events |= SELECT_R_IN;
if (rwx & SELECT_W)
events |= SELECT_W_IN;
if (rwx & SELECT_X)
events |= SELECT_X_IN;
pollwrap_add_fd_events(pw, fd, events);
}
int pollwrap_poll_instant(pollwrapper *pw)
{
return poll(pw->fds, pw->nfd, 0);
}
int pollwrap_poll_endless(pollwrapper *pw)
{
return poll(pw->fds, pw->nfd, -1);
}
int pollwrap_poll_timeout(pollwrapper *pw, int milliseconds)
{
assert(milliseconds >= 0);
return poll(pw->fds, pw->nfd, milliseconds);
}
int pollwrap_get_fd_events(pollwrapper *pw, int fd)
{
pollwrap_fdtopos *f2p, f2p_find;
assert(fd >= 0);
f2p_find.fd = fd;
f2p = find234(pw->fdtopos, &f2p_find, NULL);
if (!f2p)
return 0;
return pw->fds[f2p->pos].revents;
}
int pollwrap_get_fd_rwx(pollwrapper *pw, int fd)
{
int revents = pollwrap_get_fd_events(pw, fd);
int rwx = 0;
if (revents & SELECT_R_OUT)
rwx |= SELECT_R;
if (revents & SELECT_W_OUT)
rwx |= SELECT_W;
if (revents & SELECT_X_OUT)
rwx |= SELECT_X;
return rwx;
}