Alexandre Julliard : server: Added support for kqueue() as an alternative to poll() on FreeBSD.

Alexandre Julliard julliard at wine.codeweavers.com
Sat Aug 5 04:41:11 CDT 2006


Module: wine
Branch: refs/heads/master
Commit: c82789264b89e40c8bad49c6866d655dc1f44754
URL:    http://source.winehq.org/git/?p=wine.git;a=commit;h=c82789264b89e40c8bad49c6866d655dc1f44754

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Fri Aug  4 22:11:00 2006 +0200

server: Added support for kqueue() as an alternative to poll() on FreeBSD.

---

 configure           |   54 ++++++++++-------------
 configure.ac        |    2 +
 include/config.h.in |    6 +++
 server/fd.c         |  122 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 152 insertions(+), 32 deletions(-)

diff --git a/configure b/configure
index 90aa97e..448115d 100755
--- a/configure
+++ b/configure
@@ -4118,12 +4118,12 @@ else
     X_LIBS="$X_LIBS -L$x_libraries"
     # For Solaris; some versions of Sun CC require a space after -R and
     # others require no space.  Words are not sufficient . . . .
-    case `(uname -sr) 2>/dev/null` in
-    "SunOS 5"*)
-      { echo "$as_me:$LINENO: checking whether -R must be followed by a space" >&5
+    { echo "$as_me:$LINENO: checking whether -R must be followed by a space" >&5
 echo $ECHO_N "checking whether -R must be followed by a space... $ECHO_C" >&6; }
-      ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries"
-      cat >conftest.$ac_ext <<_ACEOF
+    ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries"
+    ac_xsave_c_werror_flag=$ac_c_werror_flag
+    ac_c_werror_flag=yes
+    cat >conftest.$ac_ext <<_ACEOF
 /* confdefs.h.  */
 _ACEOF
 cat confdefs.h >>conftest.$ac_ext
@@ -4172,23 +4172,15 @@ eval "echo \"\$as_me:$LINENO: $ac_try_ec
   ac_status=$?
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); }; }; then
-  ac_R_nospace=yes
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+       X_LIBS="$X_LIBS -R$x_libraries"
 else
   echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-	ac_R_nospace=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext \
-      conftest$ac_exeext conftest.$ac_ext
-      if test $ac_R_nospace = yes; then
-	{ echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6; }
-	X_LIBS="$X_LIBS -R$x_libraries"
-      else
 	LIBS="$ac_xsave_LIBS -R $x_libraries"
-	cat >conftest.$ac_ext <<_ACEOF
+       cat >conftest.$ac_ext <<_ACEOF
 /* confdefs.h.  */
 _ACEOF
 cat confdefs.h >>conftest.$ac_ext
@@ -4237,27 +4229,25 @@ eval "echo \"\$as_me:$LINENO: $ac_try_ec
   ac_status=$?
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); }; }; then
-  ac_R_space=yes
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+	  X_LIBS="$X_LIBS -R $x_libraries"
 else
   echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-	ac_R_space=no
+	{ echo "$as_me:$LINENO: result: neither works" >&5
+echo "${ECHO_T}neither works" >&6; }
 fi
 
 rm -f core conftest.err conftest.$ac_objext \
       conftest$ac_exeext conftest.$ac_ext
-	if test $ac_R_space = yes; then
-	  { echo "$as_me:$LINENO: result: yes" >&5
-echo "${ECHO_T}yes" >&6; }
-	  X_LIBS="$X_LIBS -R $x_libraries"
-	else
-	  { echo "$as_me:$LINENO: result: neither works" >&5
-echo "${ECHO_T}neither works" >&6; }
-	fi
-      fi
-      LIBS=$ac_xsave_LIBS
-    esac
+fi
+
+rm -f core conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+    ac_c_werror_flag=$ac_xsave_c_werror_flag
+    LIBS=$ac_xsave_LIBS
   fi
 
   # Check for system-dependent libraries X programs must link with.
@@ -8436,6 +8426,7 @@ done
 
 
 
+
 for ac_header in \
 	AudioUnit/AudioUnit.h \
 	CoreAudio/CoreAudio.h \
@@ -8504,6 +8495,7 @@ for ac_header in \
 	sys/elf32.h \
 	sys/epoll.h \
 	sys/errno.h \
+	sys/event.h \
 	sys/exec_elf.h \
 	sys/filio.h \
 	sys/ioctl.h \
@@ -19349,6 +19341,7 @@ fi
 
 
 
+
 for ac_func in \
 	_lwp_create \
 	_lwp_self \
@@ -19385,6 +19378,7 @@ for ac_func in \
 	gettimeofday \
 	getuid \
 	inet_network \
+	kqueue \
 	lstat \
 	memmove \
 	mmap \
diff --git a/configure.ac b/configure.ac
index fa74bee..f375c59 100644
--- a/configure.ac
+++ b/configure.ac
@@ -227,6 +227,7 @@ AC_CHECK_HEADERS(\
 	sys/elf32.h \
 	sys/epoll.h \
 	sys/errno.h \
+	sys/event.h \
 	sys/exec_elf.h \
 	sys/filio.h \
 	sys/ioctl.h \
@@ -1289,6 +1290,7 @@ AC_CHECK_FUNCS(\
 	gettimeofday \
 	getuid \
 	inet_network \
+	kqueue \
 	lstat \
 	memmove \
 	mmap \
diff --git a/include/config.h.in b/include/config.h.in
index 870e96c..3d1d4b5 100644
--- a/include/config.h.in
+++ b/include/config.h.in
@@ -263,6 +263,9 @@ #undef HAVE_JACK_JACK_H
 /* Define to 1 if you have the <jpeglib.h> header file. */
 #undef HAVE_JPEGLIB_H
 
+/* Define to 1 if you have the `kqueue' function. */
+#undef HAVE_KQUEUE
+
 /* Define to 1 if you have the <lber.h> header file. */
 #undef HAVE_LBER_H
 
@@ -725,6 +728,9 @@ #undef HAVE_SYS_EPOLL_H
 /* Define to 1 if you have the <sys/errno.h> header file. */
 #undef HAVE_SYS_ERRNO_H
 
+/* Define to 1 if you have the <sys/event.h> header file. */
+#undef HAVE_SYS_EVENT_H
+
 /* Define to 1 if you have the <sys/exec_elf.h> header file. */
 #undef HAVE_SYS_EXEC_ELF_H
 
diff --git a/server/fd.c b/server/fd.c
index 02aa88d..b7281a4 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -37,6 +37,11 @@ #endif
 #ifdef HAVE_SYS_POLL_H
 #include <sys/poll.h>
 #endif
+#ifdef HAVE_SYS_EVENT_H
+#include <sys/event.h>
+#undef LIST_INIT
+#undef LIST_ENTRY
+#endif
 #ifdef HAVE_STDINT_H
 #include <stdint.h>
 #endif
@@ -358,7 +363,7 @@ static int get_next_timeout(void);
 
 #ifdef USE_EPOLL
 
-static int epoll_fd;
+static int epoll_fd = -1;
 
 static inline void init_epoll(void)
 {
@@ -452,7 +457,120 @@ static inline void main_loop_epoll(void)
     }
 }
 
-#else /* USE_EPOLL */
+#elif defined(HAVE_KQUEUE)
+
+static int kqueue_fd = -1;
+
+static inline void init_epoll(void)
+{
+#ifndef __APPLE__ /* kqueue support is broken in the MacOS kernel so we can't use it */
+    kqueue_fd = kqueue();
+#endif
+}
+
+static inline void set_fd_epoll_events( struct fd *fd, int user, int events )
+{
+    struct kevent ev[2];
+
+    if (kqueue_fd == -1) return;
+
+    EV_SET( &ev[0], fd->unix_fd, EVFILT_READ, 0, NOTE_LOWAT, 1, (void *)user );
+    EV_SET( &ev[1], fd->unix_fd, EVFILT_WRITE, 0, NOTE_LOWAT, 1, (void *)user );
+
+    if (events == -1)  /* stop waiting on this fd completely */
+    {
+        if (pollfd[user].fd == -1) return;  /* already removed */
+        ev[0].flags |= EV_DELETE;
+        ev[1].flags |= EV_DELETE;
+    }
+    else if (pollfd[user].fd == -1)
+    {
+        if (pollfd[user].events) return;  /* stopped waiting on it, don't restart */
+        ev[0].flags |= EV_ADD | ((events & POLLIN) ? EV_ENABLE : EV_DISABLE);
+        ev[1].flags |= EV_ADD | ((events & POLLOUT) ? EV_ENABLE : EV_DISABLE);
+    }
+    else
+    {
+        if (pollfd[user].events == events) return;  /* nothing to do */
+        ev[0].flags |= (events & POLLIN) ? EV_ENABLE : EV_DISABLE;
+        ev[1].flags |= (events & POLLOUT) ? EV_ENABLE : EV_DISABLE;
+    }
+
+    if (kevent( kqueue_fd, ev, 2, NULL, 0, NULL ) == -1)
+    {
+        if (errno == ENOMEM)  /* not enough memory, give up on kqueue */
+        {
+            close( kqueue_fd );
+            kqueue_fd = -1;
+        }
+        else perror( "kevent" );  /* should not happen */
+    }
+}
+
+static inline void remove_epoll_user( struct fd *fd, int user )
+{
+    if (kqueue_fd == -1) return;
+
+    if (pollfd[user].fd != -1)
+    {
+        struct kevent ev[2];
+
+        EV_SET( &ev[0], fd->unix_fd, EVFILT_READ, EV_DELETE, 0, 0, 0 );
+        EV_SET( &ev[1], fd->unix_fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0 );
+        kevent( kqueue_fd, ev, 2, NULL, 0, NULL );
+    }
+}
+
+static inline void main_loop_epoll(void)
+{
+    int i, ret, timeout;
+    struct kevent events[128];
+
+    if (kqueue_fd == -1) return;
+
+    while (active_users)
+    {
+        timeout = get_next_timeout();
+
+        if (!active_users) break;  /* last user removed by a timeout */
+        if (kqueue_fd == -1) break;  /* an error occurred with kqueue */
+
+        if (timeout != -1)
+        {
+            struct timespec ts;
+
+            ts.tv_sec = timeout / 1000;
+            ts.tv_nsec = (timeout % 1000) * 1000000;
+            ret = kevent( kqueue_fd, NULL, 0, events, sizeof(events)/sizeof(events[0]), &ts );
+        }
+        else ret = kevent( kqueue_fd, NULL, 0, events, sizeof(events)/sizeof(events[0]), NULL );
+
+        /* put the events into the pollfd array first, like poll does */
+        for (i = 0; i < ret; i++)
+        {
+            long user = (long)events[i].udata;
+            pollfd[user].revents = 0;
+        }
+        for (i = 0; i < ret; i++)
+        {
+            long user = (long)events[i].udata;
+            if (events[i].filter == EVFILT_READ) pollfd[user].revents |= POLLIN;
+            else if (events[i].filter == EVFILT_WRITE) pollfd[user].revents |= POLLOUT;
+            if (events[i].flags & EV_EOF) pollfd[user].revents |= POLLHUP;
+            if (events[i].flags & EV_ERROR) pollfd[user].revents |= POLLERR;
+        }
+
+        /* read events from the pollfd array, as set_fd_events may modify them */
+        for (i = 0; i < ret; i++)
+        {
+            long user = (long)events[i].udata;
+            if (pollfd[user].revents) fd_poll_event( poll_users[user], pollfd[user].revents );
+            pollfd[user].revents = 0;
+        }
+    }
+}
+
+#else /* HAVE_KQUEUE */
 
 static inline void init_epoll(void) { }
 static inline void set_fd_epoll_events( struct fd *fd, int user, int events ) { }




More information about the wine-cvs mailing list