server: Added support for kqueue() as an alternative to poll() on FreeBSD.
diff --git a/configure b/configure
index 90aa97e..448115d 100755
--- a/configure
+++ b/configure
@@ -4118,12 +4118,12 @@
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 @@
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
- ac_R_nospace=yes
-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 "$as_me:$LINENO: result: no" >&5
echo "${ECHO_T}no" >&6; }
- X_LIBS="$X_LIBS -R$x_libraries"
- else
+ X_LIBS="$X_LIBS -R$x_libraries"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
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 @@
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
- ac_R_space=yes
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
- ac_R_space=no
-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 "$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
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ { 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
+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 @@
+
for ac_header in \
AudioUnit/AudioUnit.h \
CoreAudio/CoreAudio.h \
@@ -8504,6 +8495,7 @@
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 @@
+
for ac_func in \
_lwp_create \
_lwp_self \
@@ -19385,6 +19378,7 @@
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 @@
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 @@
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 @@
/* 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 @@
/* 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 @@
#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 @@
#ifdef USE_EPOLL
-static int epoll_fd;
+static int epoll_fd = -1;
static inline void init_epoll(void)
{
@@ -452,7 +457,120 @@
}
}
-#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 ) { }