[stgt] [PATCH 12/14] tgt: BSD builds support of sys/epoll.h via BSD's kevent
Boaz Harrosh
bharrosh at panasas.com
Mon Feb 23 19:06:25 CET 2009
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
More information about the stgt
mailing list