Adds the sys/epoll.h header file taken from the gcc-on-linux distribution. (This file does not pass checkpatch but is left as is to be synced with gcc) Implements a workable set of the <sys/epoll.h> by translating back and forth from epoll calls and constants to kevent calls and constants. Signed-off-by: Boaz Harrosh <bharrosh at panasas.com> --- bsd_include/sys/epoll.h | 119 +++++++++++++++++++++++++++++ usr/bsd_epoll.c | 189 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 308 insertions(+), 0 deletions(-) create mode 100644 bsd_include/sys/epoll.h create mode 100644 usr/bsd_epoll.c diff --git a/bsd_include/sys/epoll.h b/bsd_include/sys/epoll.h new file mode 100644 index 0000000..22b7e52 --- /dev/null +++ b/bsd_include/sys/epoll.h @@ -0,0 +1,119 @@ +/* Copyright (C) 2002,2003,2004,2005,2006,2007 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _SYS_EPOLL_H +#define _SYS_EPOLL_H 1 + +#include <stdint.h> +#include <sys/types.h> + +enum EPOLL_EVENTS + { + EPOLLIN = 0x001, +#define EPOLLIN EPOLLIN + EPOLLPRI = 0x002, +#define EPOLLPRI EPOLLPRI + EPOLLOUT = 0x004, +#define EPOLLOUT EPOLLOUT + EPOLLRDNORM = 0x040, +#define EPOLLRDNORM EPOLLRDNORM + EPOLLRDBAND = 0x080, +#define EPOLLRDBAND EPOLLRDBAND + EPOLLWRNORM = 0x100, +#define EPOLLWRNORM EPOLLWRNORM + EPOLLWRBAND = 0x200, +#define EPOLLWRBAND EPOLLWRBAND + EPOLLMSG = 0x400, +#define EPOLLMSG EPOLLMSG + EPOLLERR = 0x008, +#define EPOLLERR EPOLLERR + EPOLLHUP = 0x010, +#define EPOLLHUP EPOLLHUP + EPOLLONESHOT = (1 << 30), +#define EPOLLONESHOT EPOLLONESHOT + EPOLLET = (1 << 31) +#define EPOLLET EPOLLET + }; + + +/* Valid opcodes ( "op" parameter ) to issue to epoll_ctl(). */ +#define EPOLL_CTL_ADD 1 /* Add a file decriptor to the interface. */ +#define EPOLL_CTL_DEL 2 /* Remove a file decriptor from the interface. */ +#define EPOLL_CTL_MOD 3 /* Change file decriptor epoll_event structure. */ + + +typedef union epoll_data +{ + void *ptr; + int fd; + uint32_t u32; + uint64_t u64; +} epoll_data_t; + +struct epoll_event +{ + uint32_t events; /* Epoll events */ + epoll_data_t data; /* User data variable */ +} __attribute__ ((__packed__)); + + +__BEGIN_DECLS + +/* Creates an epoll instance. Returns an fd for the new instance. + The "size" parameter is a hint specifying the number of file + descriptors to be associated with the new instance. The fd + returned by epoll_create() should be closed with close(). */ +extern int epoll_create (int __size); + + +/* Manipulate an epoll instance "epfd". Returns 0 in case of success, + -1 in case of error ( the "errno" variable will contain the + specific error code ) The "op" parameter is one of the EPOLL_CTL_* + constants defined above. The "fd" parameter is the target of the + operation. The "event" parameter describes which events the caller + is interested in and any associated user data. */ +extern int epoll_ctl (int __epfd, int __op, int __fd, + struct epoll_event *__event); + + +/* Wait for events on an epoll instance "epfd". Returns the number of + triggered events returned in "events" buffer. Or -1 in case of + error with the "errno" variable set to the specific error code. The + "events" parameter is a buffer that will contain triggered + events. The "maxevents" is the maximum number of events to be + returned ( usually size of "events" ). The "timeout" parameter + specifies the maximum wait time in milliseconds (-1 == infinite). + + This function is a cancellation point and therefore not marked with + __THROW. */ +extern int epoll_wait (int __epfd, struct epoll_event *__events, + int __maxevents, int __timeout); + + +/* Same as epoll_wait, but the thread's signal mask is temporarily + and atomically replaced with the one provided as parameter. + + This function is a cancellation point and therefore not marked with + __THROW. */ +/*extern int epoll_pwait (int __epfd, struct epoll_event *__events, + int __maxevents, int __timeout, + __const __sigset_t *__ss); +*/ +__END_DECLS + +#endif /* sys/epoll.h */ diff --git a/usr/bsd_epoll.c b/usr/bsd_epoll.c new file mode 100644 index 0000000..621d262 --- /dev/null +++ b/usr/bsd_epoll.c @@ -0,0 +1,189 @@ +/* + * bsd_epoll.c - Linux epoll.h emulation via kevent API + * + * Copyright (c) 2009 Boaz Harrosh <bharrosh at panasas.com> + * All rights reserved. + * + * Inspired by code written by Roman Divacky + * from the freebsd's linux emulation project at linux_epoll.c file + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file implements a workable set of the <sys/epoll.h> header file + * taken from the gcc-on-linux distribution. The implementation translates + * back and forth from epoll calls and constants to Kevent calls and constants. + */ + +#include <sys/types.h> +#include <sys/event.h> +#include <sys/time.h> +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <sys/epoll.h> + +/* Create a new epoll file descriptor. */ +int epoll_create(int size) +{ + if (size <= 0) + return -EINVAL; + /* + * args->size is unused. Linux just tests it + * and then forgets it as well. + */ + + return kqueue(); +} + +static void +kevent_to_epoll(struct kevent *kevent, struct epoll_event *event) +{ + /* if (kevent->flags & EV_ERROR) { + ... Any special event flags on Errors? + } */ + + memset(event, 0, sizeof(*event)); + switch (kevent->filter) { + case EVFILT_READ: + /* in Linux EPOLLIN with Zero Data will signal a close + * condition. So do that if EV_EOF. + */ + if ((kevent->data > 0) || (kevent->flags & EV_EOF)) + event->events = EPOLLIN; + break; + case EVFILT_WRITE: + if (kevent->data > 0) + event->events = EPOLLOUT; + break; + default: + fprintf(stderr, "Unsupported kevent_to_epoll event=%d" + " data=%lx flags=0x%x ident=%ld fflags=0x%x\n", + kevent->filter, (long)kevent->data, + kevent->flags, (long)kevent->ident, + kevent->fflags); + } + event->data.ptr = kevent->udata; +} + +static void kevent_to_epoll_arr(struct kevent *kevp, int count, + struct epoll_event *eep) +{ + int i; + + for (i = 0; i < count; i++) { + kevent_to_epoll(&kevp[i], &eep[i]); + /*printf("eep[%d]=%p\n", i, eep[i].data.ptr);*/ + } +} + +/* + * Always create two filters An EVFILT_READ and an EVFILT_WRITE. + * EV_ENABLE/EV_DISABLE according to epoll flags. On EPOLL_CTL_MOD + * first delete then add a new. On EPOLL_CTL_DEL remove both. + */ +int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) +{ + struct kevent kev[2] = {{.flags = 0},}; + int read_flags, write_flags; + + switch (op) { + case EPOLL_CTL_MOD: + epoll_ctl(epfd, EPOLL_CTL_DEL, fd, event); + /* fall through */ + case EPOLL_CTL_ADD: + { + int flags; + + if ((event->events & EPOLLIN) || event->events & EPOLLPRI) + read_flags = EV_ENABLE; + else + read_flags = EV_DISABLE; + + if (event->events & EPOLLOUT) + write_flags = EV_ENABLE; + else + write_flags = EV_DISABLE; + + flags = EV_ADD; + if (event->events & EPOLLET) + flags |= EV_CLEAR; + if (event->events & EPOLLONESHOT) + flags |= EV_ONESHOT; + + read_flags |= flags; write_flags |= flags; +/* printf("%s(fd=%d data.ptr=%p\n", + op == EPOLL_CTL_MOD ? "EPOLL_CTL_MOD" : "EPOLL_CTL_ADD", + fd ,event->data.ptr); + printf(" EVFILT_READ(on=%d read_flags=0x%x\n", + read_flags & EV_ENABLE, read_flags); + printf(" EVFILT_WRITE(on=%d write_flags=0x%x);\n", + write_flags & EV_ENABLE, write_flags);*/ + } + break; + case EPOLL_CTL_DEL: + read_flags = write_flags = EV_DELETE | EV_DISABLE; + /*printf("EPOLL_CTL_DEL(fd=%d\n",fd);*/ + break; + } + + EV_SET(&kev[0], fd, EVFILT_READ, read_flags, 0, 0, + event ? event->data.ptr : 0); + EV_SET(&kev[1], fd, EVFILT_WRITE, write_flags, 0, 0, + event ? event->data.ptr : 0); + + return kevent(epfd, kev, 2, NULL, 0, NULL); +} + +/* + * Wait for a filter to be triggered on the epoll file descriptor. + */ +int epoll_wait(int epfd, struct epoll_event *events, + int maxevents, int timeout) +{ + struct kevent *kevp; + struct timespec ts; + int rc; + + /* Convert from miliseconds to timespec. */ + ts.tv_sec = timeout / 1000000; + ts.tv_nsec = (timeout % 1000000) * 1000; + + kevp = calloc(maxevents, sizeof(*kevp)); + /* + * ENOMEM is not expected from epoll_wait. + * Maybe we should translate that but I don't think it matters at all. + */ + if (!kevp) + return -ENOMEM; + + rc = kevent(epfd, NULL, 0, kevp, maxevents, &ts); + + if (rc > 0) { + /*printf("epoll_wait LEAVE %d\n", rc);*/ + kevent_to_epoll_arr(kevp, rc, events); + } + + free(kevp); + return rc; +} -- 1.6.0.6 -- To unsubscribe from this list: send the line "unsubscribe stgt" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html |