Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mRemoteNG/PuTTYNG.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'unix/utils/pollwrap.c')
-rw-r--r--unix/utils/pollwrap.c190
1 files changed, 190 insertions, 0 deletions
diff --git a/unix/utils/pollwrap.c b/unix/utils/pollwrap.c
new file mode 100644
index 00000000..51121e36
--- /dev/null
+++ b/unix/utils/pollwrap.c
@@ -0,0 +1,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;
+}