1 /* IOengine_kevent.c - IOMultiplexer
2 * Copyright (C) 2014 Philipp Kreil (pk910)
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.
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.
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/>.
17 #define _IOHandler_internals
18 #include "IOInternal.h"
19 #include "IOHandler.h"
21 #include "IOSockets.h"
23 #ifdef HAVE_SYS_EVENT_H
24 #include <sys/event.h>
31 static int engine_kevent_init() {
38 static void engine_kevent_add(struct _IOSocket *iosock) {
39 //add Socket FD to the kevent queue
40 struct kevent changes[2];
44 if (iosocket_wants_reads(iosock))
45 EV_SET(&changes[nchanges++], iosock->fd, EVFILT_READ, EV_ADD, 0, 0, iosock);
46 if (iosocket_wants_writes(iosock))
47 EV_SET(&changes[nchanges++], iosock->fd, EVFILT_WRITE, EV_ADD, 0, 0, iosock);
49 res = kevent(kevent_fd, changes, nchanges, NULL, 0, NULL);
51 iolog_trigger(IOLOG_ERROR, "could not add _IOSocket %d to kevent queue. (returned: %d)", iosock->fd, res);
54 static void engine_kevent_remove(struct _IOSocket *iosock) {
55 struct kevent changes[2];
58 EV_SET(&changes[nchanges++], iosock->fd, EVFILT_READ, EV_DELETE, 0, 0, iosock);
59 EV_SET(&changes[nchanges++], iosock->fd, EVFILT_WRITE, EV_DELETE, 0, 0, iosock);
60 kevent(kevent_fd, changes, nchanges, NULL, 0, NULL);
63 static void engine_kevent_update(struct _IOSocket *iosock) {
64 struct kevent changes[2];
68 EV_SET(&changes[nchanges++], iosock->fd, EVFILT_READ, iosocket_wants_reads(iosock) ? EV_ADD : EV_DELETE, 0, 0, iosock);
69 EV_SET(&changes[nchanges++], iosock->fd, EVFILT_WRITE, iosocket_wants_writes(iosock) ? EV_ADD : EV_DELETE, 0, 0, iosock);
71 res = kevent(kevent_fd, changes, nchanges, NULL, 0, NULL);
73 iolog_trigger(IOLOG_ERROR, "could not update _IOSocket %d in kevent queue. (returned: %d)", iosock->fd, res);
76 static void engine_kevent_loop(struct timeval *timeout) {
77 struct kevent events[MAX_EVENTS];
81 struct timeval now, tout;
84 gettimeofday(&now, NULL);
85 if(iotimer_sorted_descriptors && timeval_is_bigger(now, iotimer_sorted_descriptors->timeout))
88 //get timeout (timer or given timeout)
89 if(iotimer_sorted_descriptors) {
90 tout = iotimer_sorted_descriptors->timeout;
91 tout.tv_sec -= now.tv_sec;
92 tout.tv_usec -= now.tv_usec;
93 if(tout.tv_usec < 0) {
95 tout.tv_usec += 1000000;
99 if(!iotimer_sorted_descriptors || timeval_is_smaler((*timeout), tout)) {
100 tout.tv_usec = timeout->tv_usec;
101 tout.tv_sec = timeout->tv_sec;
104 } else if(iotimer_sorted_descriptors)
109 kevent_result = kevent(kevent_fd, NULL, 0, events, MAX_EVENTS, timeout);
111 if (kevent_result < 0) {
112 if (errno != EINTR) {
113 iolog_trigger(IOLOG_FATAL, "kevent() failed with errno %d: %s", errno, strerror(errno));
118 for(i = 0; i < kevent_result; i++)
119 iosocket_events_callback(events[i].udata, (events[i].filter == EVFILT_READ), (events[i].filter == EVFILT_WRITE));
123 gettimeofday(&now, NULL);
124 if(iotimer_sorted_descriptors && timeval_is_bigger(now, iotimer_sorted_descriptors->timeout))
128 static void engine_kevent_cleanup() {
132 struct IOEngine engine_kevent = {
134 .init = engine_kevent_init,
135 .add = engine_kevent_add,
136 .remove = engine_kevent_remove,
137 .update = engine_kevent_update,
138 .loop = engine_kevent_loop,
139 .cleanup = engine_kevent_cleanup,
144 struct IOEngine engine_kevent = {