Hi,

I've made patch for kqueue FreeBSD support, could somebody review it?


diff -Naur openvpn-2.1.4/event.c openvpn-2.1.4.new/event.c
--- openvpn-2.1.4/event.c	2010-10-21 10:37:51.000000000 -0700
+++ openvpn-2.1.4.new/event.c	2011-01-26 15:11:06.000000000 -0800
@@ -30,6 +30,10 @@
 #include "event.h"

 #include "memdbg.h"
+#define KQUEUE 1
+#if KQUEUE
+#include <sys/event.h>
+#endif

 /*
  * Some OSes will prefer select() over poll()
@@ -599,7 +603,163 @@

   return (struct event_set *) eps;
 }
-#endif /* EPOLL */
+
+#elif KQUEUE /* EPOLL */
+
+struct kq_set
+{
+  struct event_set_functions func;
+  bool fast;
+  int kqfd;
+  int maxevents;
+  struct kevent *changes;
+  size_t changes_size;
+  size_t maxchanges;
+  struct kevent *events;
+};
+
+static void
+kq_free (struct event_set *es)
+{
+  struct kq_set *kqs = (struct kq_set *) es;
+  close (kqs->kqfd);
+  free (kqs->changes);
+  free (kqs->events);
+  free (kqs);
+}
+
+static void
+kq_reset (struct event_set *es)
+{
+  const struct kq_set *kqs = (struct kq_set *) es;
+  ASSERT (kqs->fast);
+}
+
+static void
+kq_del (struct event_set *es, event_t event)
+{
+  struct kq_set *kqs = (struct kq_set *) es;
+  struct kevent *ev;
+
+  dmsg (D_EVENT_WAIT, "KQ_DEL ev=%d", (int)event);
+
+  ASSERT (!kqs->fast);
+  if ( kqs->changes_size+2 > kqs->maxchanges) {
+    kqs->maxchanges+=128;
+    kqs->changes = realloc(kqs->changes, sizeof(struct kevent)*kqs->maxchanges);
+  }
+
+  ev=&kqs->changes[kqs->changes_size++];
+  ev->ident = event;
+  ev->flags = EV_DELETE;
+  ev->filter = EVFILT_READ;
+
+  ev=&kqs->changes[kqs->changes_size++];
+  ev->ident = event;
+  ev->flags = EV_DELETE;
+  ev->filter = EVFILT_WRITE;
+}
+
+static void
+kq_ctl (struct event_set *es, event_t event, unsigned int rwflags, void *arg)
+{
+  struct kq_set *kqs = (struct kq_set *) es;
+  if ( kqs->changes_size+2 > kqs->maxchanges) {
+    kqs->maxchanges+=128;
+    kqs->changes = realloc(kqs->changes, sizeof(struct kevent)*kqs->maxchanges);
+  }
+
+  if (rwflags & EVENT_READ) {
+    struct kevent *ev=&kqs->changes[kqs->changes_size++];
+    ev->udata=arg;
+    ev->ident = event;
+    ev->flags = EV_ADD;
+    ev->filter = EVFILT_READ;
+  }
+  if (rwflags & EVENT_WRITE) {
+    struct kevent *ev=&kqs->changes[kqs->changes_size++];
+    ev->udata=arg;
+    ev->ident = event;
+    ev->flags = EV_ADD;
+    ev->filter = EVFILT_WRITE;
+  }
+}
+
+static int
+kq_wait (struct event_set *es, const struct timeval *tv, struct event_set_return *out, int outlen)
+{
+  struct kq_set *kqs = (struct kq_set *) es;
+  int stat;
+  struct timespec ts;
+  TIMEVAL_TO_TIMESPEC(tv, &ts);
+
+  if (outlen > kqs->maxevents) {
+    kqs->maxevents=outlen;
+    kqs->events = realloc(kqs->events, sizeof(struct kevent)*outlen);
+  }
+
+  stat = kevent (kqs->kqfd, kqs->changes, kqs->changes_size, kqs->events, outlen, &ts );
+  kqs->changes_size=0;
+
+  if (stat > 0)
+    {
+      int i;
+      const struct kevent *ev = kqs->events;
+      struct event_set_return *esr = out;
+      for (i = 0; i < stat; ++i)
+	{
+	  esr->rwflags = 0;
+	  if (ev->filter == EVFILT_READ)
+	    esr->rwflags |= EVENT_READ;
+	  if (ev->filter == EVFILT_WRITE)
+	    esr->rwflags |= EVENT_WRITE;
+	  esr->arg = ev->udata;
+	  dmsg (D_EVENT_WAIT, "KQ_WAIT[%d] rwflags=0x%04x ev=0x%08x arg=" ptr_format,
+	       i, esr->rwflags, ev->flags, (ptr_type)ev->udata);
+	  ++ev;
+	  ++esr;
+	}
+    }
+  return stat;
+}
+
+static struct event_set *
+kq_init (int *maxevents, unsigned int flags)
+{
+  struct kq_set *kqs;
+  int fd;
+
+  dmsg (D_EVENT_WAIT, "KQ_INIT maxevents=%d flags=0x%08x", *maxevents, flags);
+
+  /* open epoll file descriptor */
+  fd = kqueue ();
+  if (fd < 0)
+    return NULL;
+
+  ALLOC_OBJ_CLEAR (kqs, struct kq_set);
+
+  /* set dispatch functions */
+  kqs->func.free = kq_free;
+  kqs->func.reset = kq_reset;
+  kqs->func.del = kq_del;
+  kqs->func.ctl = kq_ctl;
+  kqs->func.wait = kq_wait;
+
+  /* fast method ("sort of") corresponds to epoll one-shot */
+  if (flags & EVENT_METHOD_FAST)
+    kqs->fast = true;
+
+  /* allocate space for epoll_wait return */
+  ASSERT (*maxevents > 0);
+  kqs->maxevents = *maxevents;
+  ALLOC_ARRAY_CLEAR (kqs->events, struct kevent, kqs->maxevents);
+
+  /* set epoll control fd */
+  kqs->kqfd = fd;
+
+  return (struct event_set *) kqs;
+}
+#endif

 #if POLL

@@ -1005,6 +1165,10 @@
   if (flags & EVENT_METHOD_US_TIMEOUT)
     ret = se_init (maxevents, flags); 
 #endif
+# ifdef KQUEUE
+   if (!ret)
+     ret = kq_init (maxevents, flags);
+# endif
 # ifdef SELECT_PREFERRED_OVER_POLL
    if (!ret)
      ret = se_init (maxevents, flags);
@@ -1038,6 +1202,13 @@
       msg (M_WARN, "Note: sys_epoll API is unavailable, falling back to poll/select API");
       ret = event_set_init_simple (maxevents, flags);
     }
+#elif KQUEUE
+  ret = kq_init (maxevents, flags);
+  if (!ret)
+    {
+      msg (M_WARN, "Note: sys_epoll API is unavailable, falling back to poll/select API");
+      ret = event_set_init_simple (maxevents, flags);
+    }
 #else
   ret = event_set_init_simple (maxevents, flags);
 #endif

Reply via email to