2 event.c -- epoll support for Linux
3 Copyright (C) 2012-2022 Guus Sliepen <guus@tinc-vpn.org>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "../system.h"
22 #include <sys/epoll.h>
28 static bool running = false;
29 static int epollset = 0;
31 /* NOTE: 1024 limit is only used on ancient (pre 2.6.27) kernels.
32 Decent kernels will ignore this value making it unlimited.
33 epoll_create1 might be better, but these kernels would not be supported
35 static inline void event_init(void) {
37 epollset = epoll_create(1024);
40 logger(DEBUG_ALWAYS, LOG_EMERG, "Could not initialize epoll: %s", strerror(errno));
46 static void event_deinit(void) {
53 void io_add(io_t *io, io_cb_t cb, void *data, int fd, int flags) {
66 void io_set(io_t *io, int flags) {
69 if(flags == io->flags) {
79 epoll_ctl(epollset, EPOLL_CTL_DEL, io->fd, NULL);
81 struct epoll_event ev = {
90 if(flags & IO_WRITE) {
91 ev.events |= EPOLLOUT;
92 } else if(ev.events == 0) {
97 if(epoll_ctl(epollset, EPOLL_CTL_ADD, io->fd, &ev) < 0) {
98 logger(DEBUG_ALWAYS, LOG_EMERG, "epoll_ctl failed: %s", strerror(errno));
103 void io_del(io_t *io) {
110 bool event_loop(void) {
116 struct timeval *tv = timeout_execute(&diff);
118 struct epoll_event events[MAX_EVENTS_PER_LOOP];
119 long timeout = (tv->tv_sec * 1000) + (tv->tv_usec / 1000);
121 if(timeout > INT_MAX) {
125 int n = epoll_wait(epollset, events, MAX_EVENTS_PER_LOOP, (int)timeout);
128 if(sockwouldblock(sockerrno)) {
139 unsigned int curgen = io_tree.generation;
141 for(int i = 0; i < n; i++) {
142 io_t *io = events[i].data.ptr;
144 if(events[i].events & EPOLLOUT && io->flags & IO_WRITE) {
145 io->cb(io->data, IO_WRITE);
148 if(curgen != io_tree.generation) {
152 if(events[i].events & EPOLLIN && io->flags & IO_READ) {
153 io->cb(io->data, IO_READ);
156 if(curgen != io_tree.generation) {
167 void event_exit(void) {