select.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #include "iowatcher.h"
  2. #ifdef EVENT_SELECT
  3. #include "hplatform.h"
  4. #ifdef OS_LINUX
  5. #include <sys/select.h>
  6. #endif
  7. #include "hdef.h"
  8. #include "hevent.h"
  9. #include "hsocket.h"
  10. typedef struct select_ctx_s {
  11. int max_fd;
  12. fd_set readfds;
  13. fd_set writefds;
  14. int nread;
  15. int nwrite;
  16. } select_ctx_t;
  17. int iowatcher_init(hloop_t* loop) {
  18. if (loop->iowatcher) return 0;
  19. select_ctx_t* select_ctx;
  20. SAFE_ALLOC_SIZEOF(select_ctx);
  21. select_ctx->max_fd = -1;
  22. FD_ZERO(&select_ctx->readfds);
  23. FD_ZERO(&select_ctx->writefds);
  24. select_ctx->nread = 0;
  25. select_ctx->nwrite = 0;
  26. loop->iowatcher = select_ctx;
  27. return 0;
  28. }
  29. int iowatcher_cleanup(hloop_t* loop) {
  30. SAFE_FREE(loop->iowatcher);
  31. return 0;
  32. }
  33. int iowatcher_add_event(hloop_t* loop, int fd, int events) {
  34. if (loop->iowatcher == NULL) {
  35. iowatcher_init(loop);
  36. }
  37. select_ctx_t* select_ctx = (select_ctx_t*)loop->iowatcher;
  38. if (fd > select_ctx->max_fd) {
  39. select_ctx->max_fd = fd;
  40. }
  41. if (events & READ_EVENT) {
  42. if (!FD_ISSET(fd, &select_ctx->readfds)) {
  43. FD_SET(fd, &select_ctx->readfds);
  44. select_ctx->nread++;
  45. }
  46. }
  47. if (events & WRITE_EVENT) {
  48. if (!FD_ISSET(fd, &select_ctx->writefds)) {
  49. FD_SET(fd, &select_ctx->writefds);
  50. select_ctx->nwrite++;
  51. }
  52. }
  53. return 0;
  54. }
  55. int iowatcher_del_event(hloop_t* loop, int fd, int events) {
  56. select_ctx_t* select_ctx = (select_ctx_t*)loop->iowatcher;
  57. if (select_ctx == NULL) return 0;
  58. if (fd == select_ctx->max_fd) {
  59. select_ctx->max_fd = -1;
  60. }
  61. if (events & READ_EVENT) {
  62. if (FD_ISSET(fd, &select_ctx->readfds)) {
  63. FD_CLR(fd, &select_ctx->readfds);
  64. select_ctx->nread--;
  65. }
  66. }
  67. if (events & WRITE_EVENT) {
  68. if (FD_ISSET(fd, &select_ctx->writefds)) {
  69. FD_CLR(fd, &select_ctx->writefds);
  70. select_ctx->nwrite--;
  71. }
  72. }
  73. return 0;
  74. }
  75. static int find_max_active_fd(hloop_t* loop) {
  76. hio_t* io = NULL;
  77. for (int i = loop->ios.maxsize-1; i >= 0; --i) {
  78. io = loop->ios.ptr[i];
  79. if (io && io->active && io->events) return i;
  80. }
  81. return -1;
  82. }
  83. static int remove_bad_fds(hloop_t* loop) {
  84. select_ctx_t* select_ctx = (select_ctx_t*)loop->iowatcher;
  85. if (select_ctx == NULL) return 0;
  86. int badfds = 0;
  87. int error = 0;
  88. socklen_t optlen = sizeof(error);
  89. for (int fd = 0; fd <= select_ctx->max_fd; ++fd) {
  90. if (FD_ISSET(fd, &select_ctx->readfds) ||
  91. FD_ISSET(fd, &select_ctx->writefds)) {
  92. error = 0;
  93. optlen = sizeof(int);
  94. if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*)&error, &optlen) < 0 || error != 0) {
  95. ++badfds;
  96. hio_t* io = loop->ios.ptr[fd];
  97. if (io) {
  98. hio_del(io, ALL_EVENTS);
  99. }
  100. }
  101. }
  102. }
  103. return badfds;
  104. }
  105. int iowatcher_poll_events(hloop_t* loop, int timeout) {
  106. select_ctx_t* select_ctx = (select_ctx_t*)loop->iowatcher;
  107. if (select_ctx == NULL) return 0;
  108. if (select_ctx->nread == 0 && select_ctx->nwrite == 0) {
  109. return 0;
  110. }
  111. int max_fd = select_ctx->max_fd;
  112. fd_set readfds = select_ctx->readfds;
  113. fd_set writefds = select_ctx->writefds;
  114. if (max_fd == -1) {
  115. select_ctx->max_fd = max_fd = find_max_active_fd(loop);
  116. }
  117. struct timeval tv, *tp;
  118. if (timeout == INFINITE) {
  119. tp = NULL;
  120. }
  121. else {
  122. tv.tv_sec = timeout / 1000;
  123. tv.tv_usec = (timeout % 1000) * 1000;
  124. tp = &tv;
  125. }
  126. int nselect = select(max_fd+1, &readfds, &writefds, NULL, tp);
  127. if (nselect < 0) {
  128. #ifdef OS_WIN
  129. if (WSAGetLastError() == WSAENOTSOCK) {
  130. #else
  131. if (errno == EBADF) {
  132. perror("select");
  133. #endif
  134. remove_bad_fds(loop);
  135. return -EBADF;
  136. }
  137. return nselect;
  138. }
  139. if (nselect == 0) return 0;
  140. int nevents = 0;
  141. int revents = 0;
  142. for (int fd = 0; fd <= max_fd; ++fd) {
  143. revents = 0;
  144. if (FD_ISSET(fd, &readfds)) {
  145. ++nevents;
  146. revents |= READ_EVENT;
  147. }
  148. if (FD_ISSET(fd, &writefds)) {
  149. ++nevents;
  150. revents |= WRITE_EVENT;
  151. }
  152. if (revents) {
  153. hio_t* io = loop->ios.ptr[fd];
  154. if (io) {
  155. io->revents = revents;
  156. EVENT_PENDING(io);
  157. }
  158. }
  159. if (nevents == nselect) break;
  160. }
  161. return nevents;
  162. }
  163. #endif