[IOMultiplexerV2] alpha
[NextIRCd.git] / src / IOHandler / IOEngine_epoll.c
1 /* IOEngine_epoll.c - IOMultiplexer
2  * Copyright (C) 2014  Philipp Kreil (pk910)
3  * 
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License 
15  * along with this program. If not, see <http://www.gnu.org/licenses/>. 
16  */
17 #define _IOHandler_internals
18 #include "IOInternal.h"
19 #include "IOHandler.h"
20 #include "IOLog.h"
21 #include "IOSockets.h"
22 #include "IOTimer.h"
23
24 #ifdef HAVE_SYS_EPOLL_H
25 #include <sys/epoll.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 #define MAX_EVENTS 32
31
32 static int epoll_fd;
33
34 static int engine_epoll_init() {
35         epoll_fd = epoll_create(IOHANDLER_MAX_SOCKETS);
36         if (epoll_fd < 0)
37                 return 0;
38         return 1;
39 }
40
41 static void engine_epoll_add(struct _IOSocket *iosock) {
42         //add Socket FD to the epoll queue
43         struct epoll_event evt;
44         int res;
45
46         evt.events = EPOLLHUP | EPOLLIN | (iosocket_wants_writes(iosock) ? EPOLLOUT : 0);
47         evt.data.ptr = iosock;
48         res = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, iosock->fd, &evt);
49         if(res < 0)
50                 iolog_trigger(IOLOG_ERROR, "could not add _IOSocket %d to epoll queue. (returned: %d)", iosock->fd, res);
51 }
52
53 static void engine_epoll_remove(struct _IOSocket *iosock) {
54         struct epoll_event evt;
55         epoll_ctl(epoll_fd, EPOLL_CTL_DEL, iosock->fd, &evt);
56 }
57
58 static void engine_epoll_update(struct _IOSocket *iosock) {
59         struct epoll_event evt;
60         int res;
61
62         evt.events = EPOLLHUP | EPOLLIN | (iosocket_wants_writes(iosock) ? EPOLLOUT : 0);
63         evt.data.ptr = iosock;
64         res = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, iosock->fd, &evt);
65         if(res < 0)
66                 iolog_trigger(IOLOG_ERROR, "could not update _IOSocket %d in epoll queue. (returned: %d)", iosock->fd, res);
67 }
68
69 static void engine_epoll_loop(struct timeval *timeout) {
70         struct epoll_event evts[MAX_EVENTS];
71         int msec, msec2;
72         int events;
73         int epoll_result;
74         struct timeval now;
75         
76         //check timers
77         gettimeofday(&now, NULL);
78         if(iotimer_sorted_descriptors && timeval_is_bigger(now, iotimer_sorted_descriptors->timeout))
79                 _trigger_timer();
80         
81         //get timeout (timer or given timeout)
82         if(iotimer_sorted_descriptors) {
83                 msec = (iotimer_sorted_descriptors->timeout.tv_sec - now.tv_sec) * 1000;
84                 msec += (iotimer_sorted_descriptors->timeout.tv_usec - now.tv_usec) / 1000;
85         }
86         if(timeout) {
87                 msec2 = (timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
88                 if(!iotimer_sorted_descriptors || msec2 < msec)
89                         msec = msec2;
90         } else if(!iotimer_sorted_descriptors)
91                 msec = -1;
92         
93         //epoll system call
94         epoll_result = epoll_wait(epoll_fd, evts, MAX_EVENTS, msec);
95         
96         if (epoll_result < 0) {
97                 if (errno != EINTR) {
98                         iolog_trigger(IOLOG_FATAL, "epoll_wait() failed with errno %d: %s", errno, strerror(errno));
99                         return;
100                 }
101         } else {
102                 int i;
103                 for(i = 0; i < epoll_result; i++) {
104                         events = evts[i].events;
105                         iosocket_events_callback(evts[i].data.ptr, (events & (EPOLLIN | EPOLLHUP)), (events & EPOLLOUT));
106                 }
107         }
108         
109         //check timers
110         gettimeofday(&now, NULL);
111         if(iotimer_sorted_descriptors && timeval_is_bigger(now, iotimer_sorted_descriptors->timeout))
112                 _trigger_timer();
113 }
114
115 static void engine_epoll_cleanup() {
116         close(epoll_fd);
117 }
118
119 struct IOEngine engine_epoll = {
120         .name = "epoll",
121         .init = engine_epoll_init,
122         .add = engine_epoll_add,
123         .remove = engine_epoll_remove,
124         .update = engine_epoll_update,
125         .loop = engine_epoll_loop,
126         .cleanup = engine_epoll_cleanup,
127 };
128
129 #else
130
131 struct IOEngine engine_epoll = {
132         .name = "epoll",
133         .init = NULL,
134         .add = NULL,
135         .remove = NULL,
136         .update = NULL,
137         .loop = NULL,
138         .cleanup = NULL,
139 };
140
141 #endif