1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
|
/*
* Wrapper system around poll() that lets me treat it more or less
* like select(), but avoiding the inherent limitation of select()
* that it can't handle the full range of fds that are capable of
* existing.
*
* The pollwrapper structure contains the 'struct pollfd' array passed
* to poll() itself, and also a tree234 that maps each fd to its
* location in the list, which makes it convenient to add or remove
* individual fds from the system or change what events you're
* watching for on them. So the API is _shaped_ basically like select,
* even if none of the details are identical: from outside this
* module, a pollwrapper can be used wherever you'd otherwise have had
* an fd_set.
*
* Also, this module translate between the simple select r/w/x
* classification and the richer poll flags. We have to stick to r/w/x
* in this code base, because it ports to other systems where that's
* all you get.
*/
/* On some systems this is needed to get poll.h to define eg.. POLLRDNORM */
#define _XOPEN_SOURCE
#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;
}
/* Omit any of the POLL{RD,WR}{NORM,BAND} flag values that are still
* not defined by poll.h, just in case */
#ifndef POLLRDNORM
#define POLLRDNORM 0
#endif
#ifndef POLLRDBAND
#define POLLRDBAND 0
#endif
#ifndef POLLWRNORM
#define POLLWRNORM 0
#endif
#ifndef POLLWRBAND
#define POLLWRBAND 0
#endif
#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);
}
static void pollwrap_get_fd_events_revents(pollwrapper *pw, int fd,
int *events_p, int *revents_p)
{
pollwrap_fdtopos *f2p, f2p_find;
int events = 0, revents = 0;
assert(fd >= 0);
f2p_find.fd = fd;
f2p = find234(pw->fdtopos, &f2p_find, NULL);
if (f2p) {
events = pw->fds[f2p->pos].events;
revents = pw->fds[f2p->pos].revents;
}
if (events_p)
*events_p = events;
if (revents_p)
*revents_p = revents;
}
int pollwrap_get_fd_events(pollwrapper *pw, int fd)
{
int revents;
pollwrap_get_fd_events_revents(pw, fd, NULL, &revents);
return revents;
}
int pollwrap_get_fd_rwx(pollwrapper *pw, int fd)
{
int events, revents;
pollwrap_get_fd_events_revents(pw, fd, &events, &revents);
int rwx = 0;
if ((events & POLLIN) && (revents & SELECT_R_OUT))
rwx |= SELECT_R;
if ((events & POLLOUT) && (revents & SELECT_W_OUT))
rwx |= SELECT_W;
if ((events & POLLPRI) && (revents & SELECT_X_OUT))
rwx |= SELECT_X;
return rwx;
}
|