pollwrap.c 4.8 KB

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