#include "iowatcher.h" #ifdef EVENT_EPOLL #include "hplatform.h" #include "hdef.h" #include "hevent.h" #ifdef OS_WIN #include "wepoll/wepoll.h" typedef HANDLE epoll_handle_t; #else #include typedef int epoll_handle_t; #define epoll_close(epfd) close(epfd) #endif #include "array.h" #define EVENTS_INIT_SIZE 64 ARRAY_DECL(struct epoll_event, events); typedef struct epoll_ctx_s { epoll_handle_t epfd; struct events events; } epoll_ctx_t; int iowatcher_init(hloop_t* loop) { if (loop->iowatcher) return 0; epoll_ctx_t* epoll_ctx; HV_ALLOC_SIZEOF(epoll_ctx); epoll_ctx->epfd = epoll_create(EVENTS_INIT_SIZE); events_init(&epoll_ctx->events, EVENTS_INIT_SIZE); loop->iowatcher = epoll_ctx; return 0; } int iowatcher_cleanup(hloop_t* loop) { if (loop->iowatcher == NULL) return 0; epoll_ctx_t* epoll_ctx = (epoll_ctx_t*)loop->iowatcher; epoll_close(epoll_ctx->epfd); events_cleanup(&epoll_ctx->events); HV_FREE(loop->iowatcher); return 0; } int iowatcher_add_event(hloop_t* loop, int fd, int events) { if (loop->iowatcher == NULL) { iowatcher_init(loop); } epoll_ctx_t* epoll_ctx = (epoll_ctx_t*)loop->iowatcher; hio_t* io = loop->ios.ptr[fd]; struct epoll_event ee; memset(&ee, 0, sizeof(ee)); ee.data.fd = fd; // pre events if (io->events & HV_READ) { ee.events |= EPOLLIN; } if (io->events & HV_WRITE) { ee.events |= EPOLLOUT; } // now events if (events & HV_READ) { ee.events |= EPOLLIN; } if (events & HV_WRITE) { ee.events |= EPOLLOUT; } int op = io->events == 0 ? EPOLL_CTL_ADD : EPOLL_CTL_MOD; epoll_ctl(epoll_ctx->epfd, op, fd, &ee); if (op == EPOLL_CTL_ADD) { if (epoll_ctx->events.size == epoll_ctx->events.maxsize) { events_double_resize(&epoll_ctx->events); } epoll_ctx->events.size++; } return 0; } int iowatcher_del_event(hloop_t* loop, int fd, int events) { epoll_ctx_t* epoll_ctx = (epoll_ctx_t*)loop->iowatcher; if (epoll_ctx == NULL) return 0; hio_t* io = loop->ios.ptr[fd]; struct epoll_event ee; memset(&ee, 0, sizeof(ee)); ee.data.fd = fd; // pre events if (io->events & HV_READ) { ee.events |= EPOLLIN; } if (io->events & HV_WRITE) { ee.events |= EPOLLOUT; } // now events if (events & HV_READ) { ee.events &= ~EPOLLIN; } if (events & HV_WRITE) { ee.events &= ~EPOLLOUT; } int op = ee.events == 0 ? EPOLL_CTL_DEL : EPOLL_CTL_MOD; epoll_ctl(epoll_ctx->epfd, op, fd, &ee); if (op == EPOLL_CTL_DEL) { epoll_ctx->events.size--; } return 0; } int iowatcher_poll_events(hloop_t* loop, int timeout) { epoll_ctx_t* epoll_ctx = (epoll_ctx_t*)loop->iowatcher; if (epoll_ctx == NULL) return 0; if (epoll_ctx->events.size == 0) return 0; int nepoll = epoll_wait(epoll_ctx->epfd, epoll_ctx->events.ptr, epoll_ctx->events.size, timeout); if (nepoll < 0) { if (errno == EINTR) { return 0; } perror("epoll"); return nepoll; } if (nepoll == 0) return 0; int nevents = 0; for (int i = 0; i < epoll_ctx->events.size; ++i) { struct epoll_event* ee = epoll_ctx->events.ptr + i; int fd = ee->data.fd; uint32_t revents = ee->events; if (revents) { ++nevents; hio_t* io = loop->ios.ptr[fd]; if (io) { if (revents & (EPOLLIN | EPOLLHUP | EPOLLERR)) { io->revents |= HV_READ; } if (revents & (EPOLLOUT | EPOLLHUP | EPOLLERR)) { io->revents |= HV_WRITE; } EVENT_PENDING(io); } } if (nevents == nepoll) break; } return nevents; } #endif