[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