diff --git a/configure b/configure index 90aa97e4e36..448115df4dd 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_echo\"") >&5 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 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 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. @@ -8434,6 +8424,7 @@ done + for ac_header in \ @@ -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 \ @@ -19347,6 +19339,7 @@ fi + for ac_func in \ @@ -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 fa74beeb5da..f375c5904eb 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 870e96c7b24..3d1d4b529f3 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -263,6 +263,9 @@ /* Define to 1 if you have the 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 header file. */ #undef HAVE_LBER_H @@ -725,6 +728,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_ERRNO_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_EVENT_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_EXEC_ELF_H diff --git a/server/fd.c b/server/fd.c index 02aa88d3703..b7281a40510 100644 --- a/server/fd.c +++ b/server/fd.c @@ -37,6 +37,11 @@ #ifdef HAVE_SYS_POLL_H #include #endif +#ifdef HAVE_SYS_EVENT_H +#include +#undef LIST_INIT +#undef LIST_ENTRY +#endif #ifdef HAVE_STDINT_H #include #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 ) { }