| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- #include "iowatcher.h"
- #ifdef EVENT_SELECT
- #include "hplatform.h"
- #include "hdef.h"
- #include "hevent.h"
- #include "hsocket.h"
- typedef struct select_ctx_s {
- int max_fd;
- fd_set readfds;
- fd_set writefds;
- int nread;
- int nwrite;
- } select_ctx_t;
- int iowatcher_init(hloop_t* loop) {
- if (loop->iowatcher) return 0;
- select_ctx_t* select_ctx;
- HV_ALLOC_SIZEOF(select_ctx);
- select_ctx->max_fd = -1;
- FD_ZERO(&select_ctx->readfds);
- FD_ZERO(&select_ctx->writefds);
- select_ctx->nread = 0;
- select_ctx->nwrite = 0;
- loop->iowatcher = select_ctx;
- return 0;
- }
- int iowatcher_cleanup(hloop_t* loop) {
- HV_FREE(loop->iowatcher);
- return 0;
- }
- int iowatcher_add_event(hloop_t* loop, int fd, int events) {
- if (loop->iowatcher == NULL) {
- iowatcher_init(loop);
- }
- select_ctx_t* select_ctx = (select_ctx_t*)loop->iowatcher;
- if (fd > select_ctx->max_fd) {
- select_ctx->max_fd = fd;
- }
- if (events & HV_READ) {
- if (!FD_ISSET(fd, &select_ctx->readfds)) {
- FD_SET(fd, &select_ctx->readfds);
- select_ctx->nread++;
- }
- }
- if (events & HV_WRITE) {
- if (!FD_ISSET(fd, &select_ctx->writefds)) {
- FD_SET(fd, &select_ctx->writefds);
- select_ctx->nwrite++;
- }
- }
- return 0;
- }
- int iowatcher_del_event(hloop_t* loop, int fd, int events) {
- select_ctx_t* select_ctx = (select_ctx_t*)loop->iowatcher;
- if (select_ctx == NULL) return 0;
- if (fd == select_ctx->max_fd) {
- select_ctx->max_fd = -1;
- }
- if (events & HV_READ) {
- if (FD_ISSET(fd, &select_ctx->readfds)) {
- FD_CLR(fd, &select_ctx->readfds);
- select_ctx->nread--;
- }
- }
- if (events & HV_WRITE) {
- if (FD_ISSET(fd, &select_ctx->writefds)) {
- FD_CLR(fd, &select_ctx->writefds);
- select_ctx->nwrite--;
- }
- }
- return 0;
- }
- static int find_max_active_fd(hloop_t* loop) {
- hio_t* io = NULL;
- for (int i = loop->ios.maxsize-1; i >= 0; --i) {
- io = loop->ios.ptr[i];
- if (io && io->active && io->events) return i;
- }
- return -1;
- }
- static int remove_bad_fds(hloop_t* loop) {
- select_ctx_t* select_ctx = (select_ctx_t*)loop->iowatcher;
- if (select_ctx == NULL) return 0;
- int badfds = 0;
- int error = 0;
- socklen_t optlen = sizeof(error);
- for (int fd = 0; fd <= select_ctx->max_fd; ++fd) {
- if (FD_ISSET(fd, &select_ctx->readfds) ||
- FD_ISSET(fd, &select_ctx->writefds)) {
- error = 0;
- optlen = sizeof(int);
- if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*)&error, &optlen) < 0 || error != 0) {
- ++badfds;
- hio_t* io = loop->ios.ptr[fd];
- if (io) {
- hio_del(io, HV_RDWR);
- }
- }
- }
- }
- return badfds;
- }
- int iowatcher_poll_events(hloop_t* loop, int timeout) {
- select_ctx_t* select_ctx = (select_ctx_t*)loop->iowatcher;
- if (select_ctx == NULL) return 0;
- if (select_ctx->nread == 0 && select_ctx->nwrite == 0) {
- return 0;
- }
- int max_fd = select_ctx->max_fd;
- fd_set readfds = select_ctx->readfds;
- fd_set writefds = select_ctx->writefds;
- if (max_fd == -1) {
- select_ctx->max_fd = max_fd = find_max_active_fd(loop);
- }
- struct timeval tv, *tp;
- if (timeout == INFINITE) {
- tp = NULL;
- }
- else {
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout % 1000) * 1000;
- tp = &tv;
- }
- int nselect = select(max_fd+1, &readfds, &writefds, NULL, tp);
- if (nselect < 0) {
- #ifdef OS_WIN
- if (WSAGetLastError() == WSAENOTSOCK) {
- #else
- if (errno == EBADF) {
- perror("select");
- #endif
- remove_bad_fds(loop);
- return -EBADF;
- }
- return nselect;
- }
- if (nselect == 0) return 0;
- int nevents = 0;
- int revents = 0;
- for (int fd = 0; fd <= max_fd; ++fd) {
- revents = 0;
- if (FD_ISSET(fd, &readfds)) {
- ++nevents;
- revents |= HV_READ;
- }
- if (FD_ISSET(fd, &writefds)) {
- ++nevents;
- revents |= HV_WRITE;
- }
- if (revents) {
- hio_t* io = loop->ios.ptr[fd];
- if (io) {
- io->revents = revents;
- EVENT_PENDING(io);
- }
- }
- if (nevents == nselect) break;
- }
- return nevents;
- }
- #endif
|