mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 09:58:01 +00:00
5c926d9ea4
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.
128 lines
2.8 KiB
C
128 lines
2.8 KiB
C
/*
|
|
* uxsel.c
|
|
*
|
|
* This module is a sort of all-purpose interchange for file
|
|
* descriptors. At one end it talks to uxnet.c and pty.c and
|
|
* anything else which might have one or more fds that need
|
|
* select() or poll()-type things doing to them during an extended
|
|
* program run; at the other end it talks to pterm.c or uxplink.c or
|
|
* anything else which might have its own means of actually doing
|
|
* those select()-type things.
|
|
*/
|
|
|
|
#include <assert.h>
|
|
|
|
#include "putty.h"
|
|
#include "tree234.h"
|
|
|
|
struct fd {
|
|
int fd;
|
|
int rwx; /* 4=except 2=write 1=read */
|
|
uxsel_callback_fn callback;
|
|
uxsel_id *id; /* for uxsel_input_remove */
|
|
};
|
|
|
|
static tree234 *fds;
|
|
|
|
static int uxsel_fd_cmp(void *av, void *bv)
|
|
{
|
|
struct fd *a = (struct fd *)av;
|
|
struct fd *b = (struct fd *)bv;
|
|
if (a->fd < b->fd)
|
|
return -1;
|
|
if (a->fd > b->fd)
|
|
return +1;
|
|
return 0;
|
|
}
|
|
static int uxsel_fd_findcmp(void *av, void *bv)
|
|
{
|
|
int *a = (int *)av;
|
|
struct fd *b = (struct fd *)bv;
|
|
if (*a < b->fd)
|
|
return -1;
|
|
if (*a > b->fd)
|
|
return +1;
|
|
return 0;
|
|
}
|
|
|
|
void uxsel_init(void)
|
|
{
|
|
fds = newtree234(uxsel_fd_cmp);
|
|
}
|
|
|
|
/*
|
|
* Here is the interface to fd-supplying modules. They supply an
|
|
* fd, a set of read/write/execute states, and a callback function
|
|
* for when the fd satisfies one of those states. Repeated calls to
|
|
* uxsel_set on the same fd are perfectly legal and serve to change
|
|
* the rwx state (typically you only want to select an fd for
|
|
* writing when you actually have pending data you want to write to
|
|
* it!).
|
|
*/
|
|
|
|
void uxsel_set(int fd, int rwx, uxsel_callback_fn callback)
|
|
{
|
|
struct fd *newfd;
|
|
|
|
assert(fd >= 0);
|
|
|
|
uxsel_del(fd);
|
|
|
|
if (rwx) {
|
|
newfd = snew(struct fd);
|
|
newfd->fd = fd;
|
|
newfd->rwx = rwx;
|
|
newfd->callback = callback;
|
|
newfd->id = uxsel_input_add(fd, rwx);
|
|
add234(fds, newfd);
|
|
}
|
|
}
|
|
|
|
void uxsel_del(int fd)
|
|
{
|
|
struct fd *oldfd = find234(fds, &fd, uxsel_fd_findcmp);
|
|
if (oldfd) {
|
|
if (oldfd->id)
|
|
uxsel_input_remove(oldfd->id);
|
|
del234(fds, oldfd);
|
|
sfree(oldfd);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* And here is the interface to select-functionality-supplying
|
|
* modules.
|
|
*/
|
|
|
|
int next_fd(int *state, int *rwx)
|
|
{
|
|
struct fd *fd;
|
|
fd = index234(fds, (*state)++);
|
|
if (fd) {
|
|
*rwx = fd->rwx;
|
|
return fd->fd;
|
|
} else
|
|
return -1;
|
|
}
|
|
|
|
int first_fd(int *state, int *rwx)
|
|
{
|
|
*state = 0;
|
|
return next_fd(state, rwx);
|
|
}
|
|
|
|
void select_result(int fd, int event)
|
|
{
|
|
struct fd *fdstruct = find234(fds, &fd, uxsel_fd_findcmp);
|
|
|
|
noise_ultralight(NOISE_SOURCE_IOID, fd);
|
|
|
|
/*
|
|
* Apparently this can sometimes be NULL. Can't see how, but I
|
|
* assume it means I need to ignore the event since it's on an
|
|
* fd I've stopped being interested in. Sigh.
|
|
*/
|
|
if (fdstruct)
|
|
fdstruct->callback(fd, event);
|
|
}
|