1#include "fdevent.h" 2#include "buffer.h" 3#include "log.h" 4 5#include <sys/types.h> 6 7#include <unistd.h> 8#include <stdlib.h> 9#include <stdio.h> 10#include <string.h> 11#include <errno.h> 12#include <signal.h> 13#include <fcntl.h> 14 15#ifdef USE_LINUX_EPOLL 16 17# include <sys/epoll.h> 18 19static void fdevent_linux_sysepoll_free(fdevents *ev) { 20 close(ev->epoll_fd); 21 free(ev->epoll_events); 22} 23 24static int fdevent_linux_sysepoll_event_del(fdevents *ev, int fde_ndx, int fd) { 25 struct epoll_event ep; 26 27 if (fde_ndx < 0) return -1; 28 29 memset(&ep, 0, sizeof(ep)); 30 31 ep.data.fd = fd; 32 ep.data.ptr = NULL; 33 34 if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fd, &ep)) { 35 log_error_write(ev->srv, __FILE__, __LINE__, "SSS", 36 "epoll_ctl failed: ", strerror(errno), ", dying"); 37 38 SEGFAULT(); 39 40 return 0; 41 } 42 43 44 return -1; 45} 46 47static int fdevent_linux_sysepoll_event_set(fdevents *ev, int fde_ndx, int fd, int events) { 48 struct epoll_event ep; 49 int add = 0; 50 51 if (fde_ndx == -1) add = 1; 52 53 memset(&ep, 0, sizeof(ep)); 54 55 ep.events = 0; 56 57 if (events & FDEVENT_IN) ep.events |= EPOLLIN; 58 if (events & FDEVENT_OUT) ep.events |= EPOLLOUT; 59 60 /** 61 * 62 * with EPOLLET we don't get a FDEVENT_HUP 63 * if the close is delay after everything has 64 * sent. 65 * 66 */ 67 68 ep.events |= EPOLLERR | EPOLLHUP /* | EPOLLET */; 69 70 ep.data.ptr = NULL; 71 ep.data.fd = fd; 72 73 if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, fd, &ep)) { 74 log_error_write(ev->srv, __FILE__, __LINE__, "SSS", 75 "epoll_ctl failed: ", strerror(errno), ", dying"); 76 77 SEGFAULT(); 78 79 return 0; 80 } 81 82 return fd; 83} 84 85static int fdevent_linux_sysepoll_poll(fdevents *ev, int timeout_ms) { 86 return epoll_wait(ev->epoll_fd, ev->epoll_events, ev->maxfds, timeout_ms); 87} 88 89static int fdevent_linux_sysepoll_event_get_revent(fdevents *ev, size_t ndx) { 90 int events = 0, e; 91 92 e = ev->epoll_events[ndx].events; 93 if (e & EPOLLIN) events |= FDEVENT_IN; 94 if (e & EPOLLOUT) events |= FDEVENT_OUT; 95 if (e & EPOLLERR) events |= FDEVENT_ERR; 96 if (e & EPOLLHUP) events |= FDEVENT_HUP; 97 if (e & EPOLLPRI) events |= FDEVENT_PRI; 98 99 return events; 100} 101 102static int fdevent_linux_sysepoll_event_get_fd(fdevents *ev, size_t ndx) { 103# if 0 104 log_error_write(ev->srv, __FILE__, __LINE__, "SD, D", 105 "fdevent_linux_sysepoll_event_get_fd: ", (int) ndx, ev->epoll_events[ndx].data.fd); 106# endif 107 108 return ev->epoll_events[ndx].data.fd; 109} 110 111static int fdevent_linux_sysepoll_event_next_fdndx(fdevents *ev, int ndx) { 112 size_t i; 113 114 UNUSED(ev); 115 116 i = (ndx < 0) ? 0 : ndx + 1; 117 118 return i; 119} 120 121int fdevent_linux_sysepoll_init(fdevents *ev) { 122 ev->type = FDEVENT_HANDLER_LINUX_SYSEPOLL; 123#define SET(x) \ 124 ev->x = fdevent_linux_sysepoll_##x; 125 126 SET(free); 127 SET(poll); 128 129 SET(event_del); 130 SET(event_set); 131 132 SET(event_next_fdndx); 133 SET(event_get_fd); 134 SET(event_get_revent); 135 136 if (-1 == (ev->epoll_fd = epoll_create(ev->maxfds))) { 137 log_error_write(ev->srv, __FILE__, __LINE__, "SSS", 138 "epoll_create failed (", strerror(errno), "), try to set server.event-handler = \"poll\" or \"select\""); 139 140 return -1; 141 } 142 143 fd_close_on_exec(ev->epoll_fd); 144 145 ev->epoll_events = malloc(ev->maxfds * sizeof(*ev->epoll_events)); 146 147 return 0; 148} 149 150#else 151int fdevent_linux_sysepoll_init(fdevents *ev) { 152 UNUSED(ev); 153 154 log_error_write(ev->srv, __FILE__, __LINE__, "S", 155 "linux-sysepoll not supported, try to set server.event-handler = \"poll\" or \"select\""); 156 157 return -1; 158} 159#endif 160