/*
* Copyright (C) 2016-2020 Red Hat, Inc. All rights reserved.
*
* Author: Jan Friesse <jfriesse@redhat.com>
*
* This software licensed under LGPL-2.0+
*/
#include "config.h"
#include <unistd.h>
#include <errno.h>
#include <sys/syscall.h>
#include "compat.h"
#ifndef HAVE_SYS_EPOLL_H
#ifdef HAVE_KEVENT
/* for FreeBSD which has kevent instead of epoll */
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#include <errno.h>
static int32_t
_poll_to_filter_(int32_t event)
{
int32_t out = 0;
if (event & POLLIN)
out |= EVFILT_READ;
if (event & POLLOUT)
out |= EVFILT_WRITE;
return out;
}
int epoll_create(int size)
{
return kqueue();
}
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
{
int ret = 0;
struct kevent ke;
short filters = _poll_to_filter_(event->events);
switch (op) {
/* The kevent man page says that EV_ADD also does MOD */
case EPOLL_CTL_ADD:
case EPOLL_CTL_MOD:
EV_SET(&ke, fd, filters, EV_ADD | EV_ENABLE, 0, 0, event->data.ptr);
break;
case EPOLL_CTL_DEL:
EV_SET(&ke, fd, filters, EV_DELETE, 0, 0, event->data.ptr);
break;
default:
errno = EINVAL;
return -1;
}
ret = kevent(epfd, &ke, 1, NULL, 0, NULL);
return ret;
}
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout_ms)
{
struct kevent kevents[maxevents];
struct timespec timeout = { 0, 0 };
struct timespec *timeout_ptr = &timeout;
uint32_t revents;
int event_count;
int i;
int returned_events;
if (timeout_ms != -1) {
timeout.tv_sec = timeout_ms/1000;
timeout.tv_nsec += (timeout_ms % 1000) * 1000000ULL;
}
else {
timeout_ptr = NULL;
}
event_count = kevent(epfd, NULL, 0, kevents, maxevents, timeout_ptr);
if (event_count == -1) {
return -1;
}
returned_events = 0;
for (i = 0; i < event_count; i++) {
revents = 0;
if (kevents[i].flags & EV_ERROR) {
revents |= POLLERR;
}
if (kevents[i].flags & EV_EOF) {
revents |= POLLHUP;
}
if (kevents[i].filter == EVFILT_READ) {
revents |= POLLIN;
}
if (kevents[i].filter == EVFILT_WRITE) {
revents |= POLLOUT;
}
events[returned_events].events = revents;
events[returned_events].data.ptr = kevents[i].udata;
returned_events++;
}
return returned_events;
}
#endif /* HAVE_KEVENT */
#endif /* HAVE_SYS_EPOLL_H */