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 EV_SET(&changes[nchanges++], iosock->fd, EVFILT_READ, EV_ADD, 0, 0, iosock);
45 if (iosocket_wants_writes(iosock))
46 EV_SET(&changes[nchanges++], iosock->fd, EVFILT_WRITE, EV_ADD, 0, 0, iosock);
48 res = kevent(kevent_fd, changes, nchanges, NULL, 0, NULL);
50 iolog_trigger(IOLOG_ERROR, "could not add _IOSocket %d to kevent queue. (returned: %d)", iosock->fd, res);
53 static void engine_kevent_remove(struct _IOSocket *iosock) {
54 struct kevent changes[2];
57 EV_SET(&changes[nchanges++], iosock->fd, EVFILT_READ, EV_DELETE, 0, 0, iosock);
58 EV_SET(&changes[nchanges++], iosock->fd, EVFILT_WRITE, EV_DELETE, 0, 0, iosock);
59 kevent(kevent_fd, changes, nchanges, NULL, 0, NULL);
62 static void engine_kevent_update(struct _IOSocket *iosock) {
63 struct kevent changes[2];
67 EV_SET(&changes[nchanges++], iosock->fd, EVFILT_READ, EV_ADD, 0, 0, iosock);
68 EV_SET(&changes[nchanges++], iosock->fd, EVFILT_WRITE, iosocket_wants_writes(iosock) ? EV_ADD : EV_DELETE, 0, 0, iosock);
70 res = kevent(kevent_fd, changes, nchanges, NULL, 0, NULL);
72 iolog_trigger(IOLOG_ERROR, "could not update _IOSocket %d in kevent queue. (returned: %d)", iosock->fd, res);
75 static void engine_kevent_loop(struct timeval *timeout) {
76 struct kevent events[MAX_EVENTS];
80 struct timeval now, tout;
83 gettimeofday(&now, NULL);
84 if(iotimer_sorted_descriptors && timeval_is_bigger(now, iotimer_sorted_descriptors->timeout))
87 //get timeout (timer or given timeout)
88 if(iotimer_sorted_descriptors) {
89 tout = iotimer_sorted_descriptors->timeout;
90 tout.tv_sec -= now.tv_sec;
91 tout.tv_usec -= now.tv_usec;
92 if(tout.tv_usec < 0) {
94 tout.tv_usec += 1000000;
98 if(!iotimer_sorted_descriptors || timeval_is_smaler((*timeout), tout)) {
99 tout.tv_usec = timeout->tv_usec;
100 tout.tv_sec = timeout->tv_sec;
103 } else if(iotimer_sorted_descriptors)
108 kevent_result = kevent(kevent_fd, NULL, 0, events, MAX_EVENTS, timeout);
110 if (kevent_result < 0) {
111 if (errno != EINTR) {
112 iolog_trigger(IOLOG_FATAL, "kevent() failed with errno %d: %s", errno, strerror(errno));
117 for(i = 0; i < kevent_result; i++)
118 iosocket_events_callback(events[i].udata, (events[i].filter == EVFILT_READ), (events[i].filter == EVFILT_WRITE));
122 gettimeofday(&now, NULL);
123 if(iotimer_sorted_descriptors && timeval_is_bigger(now, iotimer_sorted_descriptors->timeout))
127 static void engine_kevent_cleanup() {
131 struct IOEngine engine_kevent = {
133 .init = engine_kevent_init,
134 .add = engine_kevent_add,
135 .remove = engine_kevent_remove,
136 .update = engine_kevent_update,
137 .loop = engine_kevent_loop,
138 .cleanup = engine_kevent_cleanup,
143 struct IOEngine engine_kevent = {