apr-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jerenkra...@apache.org
Subject cvs commit: apr/test testpoll.c
Date Tue, 06 Jul 2004 03:38:06 GMT
jerenkrantz    2004/07/05 20:38:06

  Modified:    .        CHANGES configure.in
               poll/unix poll.c
               test     testpoll.c
  Log:
  Add support for KQueue and sys_epoll to apr_pollset.
  
  (Justin tweaked the cleanup code from Paul's last posted patch.)
  
  Submitted by:	Paul Querna
  Reviewed by:	Justin Erenkrantz, Joe Orton
  
  Revision  Changes    Path
  1.480     +2 -0      apr/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/apr/CHANGES,v
  retrieving revision 1.479
  retrieving revision 1.480
  diff -u -u -r1.479 -r1.480
  --- CHANGES	4 Jul 2004 23:38:18 -0000	1.479
  +++ CHANGES	6 Jul 2004 03:38:06 -0000	1.480
  @@ -7,6 +7,8 @@
   
   Changes with APR 1.0
   
  +  *) Add support for KQueue and sys_epoll to apr_pollset.  [Paul Querna]
  +
     *) Support threading on FreeBSD 5.x where kern.osreldate >= 502102.
        [Craig Rodrigues <rodrigc crodrigues.org>]
   
  
  
  
  1.594     +19 -0     apr/configure.in
  
  Index: configure.in
  ===================================================================
  RCS file: /home/cvs/apr/configure.in,v
  retrieving revision 1.593
  retrieving revision 1.594
  diff -u -u -r1.593 -r1.594
  --- configure.in	30 Jun 2004 13:16:54 -0000	1.593
  +++ configure.in	6 Jul 2004 03:38:06 -0000	1.594
  @@ -638,6 +638,25 @@
   
   AC_CHECK_FUNCS(poll)
   
  +# Checks for the FreeBSD KQueue and Linux epoll interfaces:
  +AC_CHECK_FUNC(kevent, 
  +  [AC_DEFINE([HAVE_KQUEUE], 1, [Define if the KQueue interface is supported])])
  +
  +# epoll* may be available in libc but return ENOSYS on a pre-2.6 kernel.
  +AC_CACHE_CHECK([for epoll support], [apr_cv_epoll],
  +[AC_TRY_RUN([
  +#include <sys/epoll.h>
  +#include <unistd.h>
  +
  +int main()
  +{
  +    return epoll_create(5) == -1;
  +}], [apr_cv_epoll=yes], [apr_cv_epoll=no], [apr_cv_epoll=no])])
  +
  +if test "$apr_cv_epoll" = "yes"; then
  +   AC_DEFINE([HAVE_EPOLL], 1, [Define if the epoll interface is supported])
  +fi
  +
   dnl ----------------------------- Checking for missing POSIX thread functions
   AC_CHECK_FUNCS([getpwnam_r getpwuid_r getgrnam_r getgrgid_r])
   
  
  
  
  1.45      +355 -12   apr/poll/unix/poll.c
  
  Index: poll.c
  ===================================================================
  RCS file: /home/cvs/apr/poll/unix/poll.c,v
  retrieving revision 1.44
  retrieving revision 1.45
  diff -u -u -r1.44 -r1.45
  --- poll.c	13 Feb 2004 09:38:33 -0000	1.44
  +++ poll.c	6 Jul 2004 03:38:06 -0000	1.45
  @@ -26,12 +26,77 @@
   #include <sys/poll.h>
   #endif
   
  +#ifdef HAVE_KQUEUE
  +#include <sys/types.h>
  +#include <sys/event.h>
  +#include <sys/time.h>
  +#endif
  +
  +#ifdef HAVE_EPOLL
  +#include <sys/epoll.h>
  +#endif
   
   #ifdef NETWARE
   #define HAS_SOCKETS(dt) (dt == APR_POLL_SOCKET) ? 1 : 0
   #define HAS_PIPES(dt) (dt == APR_POLL_FILE) ? 1 : 0
   #endif
   
  +#ifdef HAVE_KQUEUE
  +static apr_int16_t get_kqueue_revent(apr_int16_t event, apr_int16_t flags)
  +{
  +    apr_int16_t rv = 0;
  +
  +    if (event & EVFILT_READ)
  +        rv |= APR_POLLIN;
  +    if (event & EVFILT_WRITE)
  +        rv |= APR_POLLOUT;
  +    if (flags & EV_ERROR || flags & EV_EOF)
  +        rv |= APR_POLLERR;
  +
  +    return rv;
  +}
  +
  +#endif
  +
  +#ifdef HAVE_EPOLL
  +static apr_int16_t get_epoll_event(apr_int16_t event)
  +{
  +    apr_int16_t rv = 0;
  +
  +    if (event & APR_POLLIN)
  +        rv |= EPOLLIN;
  +    if (event & APR_POLLPRI)
  +        rv |= EPOLLPRI;
  +    if (event & APR_POLLOUT)
  +        rv |= EPOLLOUT;
  +    if (event & APR_POLLERR)
  +        rv |= EPOLLERR;
  +    if (event & APR_POLLHUP)
  +        rv |= EPOLLHUP;
  +    /* APR_POLLNVAL is not handled by epoll. */
  +
  +    return rv;
  +}
  +
  +static apr_int16_t get_epoll_revent(apr_int16_t event)
  +{
  +    apr_int16_t rv = 0;
  +
  +    if (event & EPOLLIN)
  +        rv |= APR_POLLIN;
  +    if (event & EPOLLPRI)
  +        rv |= APR_POLLPRI;
  +    if (event & EPOLLOUT)
  +        rv |= APR_POLLOUT;
  +    if (event & EPOLLERR)
  +        rv |= APR_POLLERR;
  +    if (event & EPOLLHUP)
  +        rv |= APR_POLLHUP;
  +    /* APR_POLLNVAL is not handled by epoll. */
  +
  +    return rv;
  +}
  +#endif
   
   #ifdef HAVE_POLL    /* We can just use poll to do our socket polling. */
   
  @@ -284,9 +349,18 @@
   #endif 
   
   struct apr_pollset_t {
  +    apr_pool_t *pool;
  +
       apr_uint32_t nelts;
       apr_uint32_t nalloc;
  -#ifdef HAVE_POLL
  +#ifdef HAVE_KQUEUE
  +    int kqueue_fd;
  +    struct kevent kevent;
  +    struct kevent *ke_set;
  +#elif defined(HAVE_EPOLL)
  +    int epoll_fd;
  +    struct epoll_event *pollset;
  +#elif defined(HAVE_POLL)
       struct pollfd *pollset;
   #else
       fd_set readset, writeset, exceptset;
  @@ -300,12 +374,23 @@
   #endif
   };
   
  +static apr_status_t backend_cleanup(void *p_)
  +{
  +    apr_pollset_t *pollset = (apr_pollset_t *)p_;
  +#ifdef HAVE_KQUEUE
  +    close(pollset->kqueue_fd);
  +#elif defined(HAVE_EPOLL)
  +    close(pollset->epoll_fd);
  +#endif
  +    return APR_SUCCESS;
  +}
  +
   APR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset,
                                                apr_uint32_t size,
                                                apr_pool_t *p,
                                                apr_uint32_t flags)
   {
  -#if !defined(HAVE_POLL) && defined(FD_SETSIZE)
  +#if !defined(HAVE_KQUEUE) && !defined(HAVE_EPOLL) && !defined(HAVE_POLL)
&& defined(FD_SETSIZE)
       if (size > FD_SETSIZE) {
           *pollset = NULL;
           return APR_EINVAL;
  @@ -314,7 +399,22 @@
       *pollset = apr_palloc(p, sizeof(**pollset));
       (*pollset)->nelts = 0;
       (*pollset)->nalloc = size;
  -#ifdef HAVE_POLL
  +    (*pollset)->pool = p;
  +#ifdef HAVE_KQUEUE
  +    (*pollset)->ke_set = (struct kevent*)apr_palloc(p, size * sizeof(struct  kevent));
  +    memset((*pollset)->ke_set, 0, size * sizeof(struct kevent));
  +    (*pollset)->kqueue_fd = kqueue();
  +    if ((*pollset)->kqueue_fd == -1) {
  +         return APR_ENOMEM;
  +    }
  +    apr_pool_cleanup_register(p, (void*)(*pollset), backend_cleanup, 
  +        apr_pool_cleanup_null);
  +#elif defined(HAVE_EPOLL)
  +    (*pollset)->epoll_fd = epoll_create(size);
  +    (*pollset)->pollset = apr_palloc(p, size * sizeof(struct epoll_event));
  +    apr_pool_cleanup_register(p, (void*)(*pollset), backend_cleanup, 
  +        apr_pool_cleanup_null);
  +#elif defined(HAVE_POLL)
       (*pollset)->pollset = apr_palloc(p, size * sizeof(struct pollfd));
   #else
       FD_ZERO(&((*pollset)->readset));
  @@ -333,25 +433,71 @@
   
   APR_DECLARE(apr_status_t) apr_pollset_destroy(apr_pollset_t *pollset)
   {
  -    /* A no-op function for now.  If we later implement /dev/poll
  -     * support, we'll need to close the /dev/poll fd here
  -     */
  -    return APR_SUCCESS;
  +    return apr_pool_cleanup_run(pollset->pool, pollset, backend_cleanup);
   }
   
   APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset,
                                             const apr_pollfd_t *descriptor)
   {
  -#ifndef HAVE_POLL
  +#ifdef HAVE_KQUEUE
  +    apr_os_sock_t fd;
  +#elif defined(HAVE_EPOLL)
  +    struct epoll_event ev;
  +    int ret = -1;
  +#else
  +#if !defined(HAVE_POLL)
       apr_os_sock_t fd;
   #endif
  +#endif
   
       if (pollset->nelts == pollset->nalloc) {
           return APR_ENOMEM;
       }
   
       pollset->query_set[pollset->nelts] = *descriptor;
  -#ifdef HAVE_POLL
  +
  +#ifdef HAVE_KQUEUE
  +    if (descriptor->desc_type == APR_POLL_SOCKET) {
  +        fd = descriptor->desc.s->socketdes;
  +    }
  +    else {
  +        fd = descriptor->desc.f->filedes;
  +    }
  +
  +    if (descriptor->reqevents & APR_POLLIN) {
  +        EV_SET(&pollset->kevent, fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
  +
  +        if (kevent(pollset->kqueue_fd, &pollset->kevent, 1, NULL, 0,
  +                   NULL) == -1) {
  +            return APR_ENOMEM;
  +        }
  +    }
  +
  +    if (descriptor->reqevents & APR_POLLOUT) {
  +        EV_SET(&pollset->kevent, fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
  +
  +        if (kevent(pollset->kqueue_fd, &pollset->kevent, 1, NULL, 0,
  +                   NULL) == -1) {
  +            return APR_ENOMEM;
  +        }
  +    }
  +
  +#elif defined(HAVE_EPOLL)
  +    ev.events = get_epoll_event(descriptor->reqevents);
  +    if (descriptor->desc_type == APR_POLL_SOCKET) {
  +        ev.data.fd = descriptor->desc.s->socketdes;
  +        ret = epoll_ctl(pollset->epoll_fd, EPOLL_CTL_ADD,
  +                        descriptor->desc.s->socketdes, &ev);
  +    }
  +    else {
  +        ev.data.fd = descriptor->desc.f->filedes;
  +        ret = epoll_ctl(pollset->epoll_fd, EPOLL_CTL_ADD,
  +                        descriptor->desc.f->filedes, &ev);
  +    }
  +    if (0 != ret) {
  +        return APR_EBADF;
  +    }
  +#elif defined(HAVE_POLL)
   
       if (descriptor->desc_type == APR_POLL_SOCKET) {
           pollset->pollset[pollset->nelts].fd = descriptor->desc.s->socketdes;
  @@ -420,11 +566,97 @@
                                                const apr_pollfd_t *descriptor)
   {
       apr_uint32_t i;
  -#ifndef HAVE_POLL
  +#ifdef HAVE_KQUEUE
  +    apr_os_sock_t fd;
  +#elif defined(HAVE_EPOLL)
  +    struct epoll_event ev;
  +    int ret = -1;
  +#elif defined(HAVE_POLL)
       apr_os_sock_t fd;
   #endif
   
  -#ifdef HAVE_POLL
  +#ifdef HAVE_KQUEUE
  +    for (i = 0; i < pollset->nelts; i++) {
  +        if (descriptor->desc.s == pollset->query_set[i].desc.s) {
  +            /* Found an instance of the fd: remove this and any other copies  */
  +            apr_uint32_t dst = i;
  +            apr_uint32_t old_nelts = pollset->nelts;
  +            pollset->nelts--;
  +            for (i++; i < old_nelts; i++) {
  +                if (descriptor->desc.s == pollset->query_set[i].desc.s) {
  +                    pollset->nelts--;
  +                }
  +                else {
  +                    pollset->query_set[dst] = pollset->query_set[i];
  +                    dst++;
  +                }
  +            }
  +
  +            if (descriptor->desc_type == APR_POLL_SOCKET) {
  +                fd = descriptor->desc.s->socketdes;
  +            }
  +            else {
  +                fd = descriptor->desc.f->filedes;
  +            }
  +
  +            if (descriptor->reqevents & APR_POLLIN) {
  +                EV_SET(&pollset->kevent, fd,
  +                       EVFILT_READ, EV_DELETE, 0, 0, NULL);
  +
  +                if (kevent(pollset->kqueue_fd, &pollset->kevent, 1, NULL, 0,
  +                          NULL) == -1) {
  +                    return APR_EBADF;
  +                }
  +            }
  +
  +            if (descriptor->reqevents & APR_POLLOUT) {
  +                EV_SET(&pollset->kevent, fd,
  +                       EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
  +
  +                if (kevent(pollset->kqueue_fd, &pollset->kevent, 1, NULL, 0,
  +                          NULL) == -1) {
  +                    return APR_EBADF;
  +                }
  +            }
  +
  +            return APR_SUCCESS;
  +        }
  +    }
  +#elif defined(HAVE_EPOLL)
  +    for (i = 0; i < pollset->nelts; i++) {
  +        if (descriptor->desc.s == pollset->query_set[i].desc.s) {
  +            /* Found an instance of the fd: remove this and any other copies  */
  +            apr_uint32_t dst = i;
  +            apr_uint32_t old_nelts = pollset->nelts;
  +            pollset->nelts--;
  +            for (i++; i < old_nelts; i++) {
  +                if (descriptor->desc.s == pollset->query_set[i].desc.s) {
  +                    pollset->nelts--;
  +                }
  +                else {
  +                    pollset->query_set[dst] = pollset->query_set[i];
  +                    dst++;
  +                }
  +            }
  +            ev.events = get_epoll_event(descriptor->reqevents);
  +            if (descriptor->desc_type == APR_POLL_SOCKET) {
  +                ev.data.fd = descriptor->desc.s->socketdes;
  +                ret = epoll_ctl(pollset->epoll_fd, EPOLL_CTL_DEL,
  +                                descriptor->desc.s->socketdes, &ev);
  +            }
  +            else {
  +                ev.data.fd = descriptor->desc.f->filedes;
  +                ret = epoll_ctl(pollset->epoll_fd, EPOLL_CTL_DEL,
  +                                descriptor->desc.f->filedes, &ev);
  +            }
  +            if (ret < 0) {
  +                return APR_EBADF;
  +            }
  +
  +            return APR_SUCCESS;
  +        }
  +    }
  +#elif defined(HAVE_POLL)
       for (i = 0; i < pollset->nelts; i++) {
           if (descriptor->desc.s == pollset->query_set[i].desc.s) {
               /* Found an instance of the fd: remove this and any other copies */
  @@ -485,8 +717,119 @@
   
       return APR_NOTFOUND;
   }
  +#ifdef HAVE_KQUEUE
  +APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset,
  +                                           apr_interval_time_t timeout,
  +                                           apr_int32_t *num,
  +                                           const apr_pollfd_t **descriptors)
  +{
  +    int rv;
  +    apr_uint32_t i, j, r = 0;
  +    struct timespec tv, *tvptr;
   
  -#ifdef HAVE_POLL
  +    if (timeout < 0) {
  +        tvptr = NULL;
  +    }
  +    else {
  +        tv.tv_sec = (long)apr_time_sec(timeout);
  +        tv.tv_nsec = (long)apr_time_msec(timeout);
  +        tvptr = &tv;
  +    }
  +
  +    rv = kevent(pollset->kqueue_fd, NULL, 0, pollset->ke_set, pollset->nelts,
  +                tvptr);
  +    (*num) = rv;
  +    if (rv < 0) {
  +        return apr_get_netos_error();
  +    }
  +    if (rv == 0) {
  +        return APR_TIMEUP;
  +    }
  +
  +    /* TODO: Is there a better way to re-associate our data? */
  +    for (i = 0; i < pollset->nelts; i++) {
  +        apr_os_sock_t fd;
  +        if (pollset->query_set[i].desc_type == APR_POLL_SOCKET) {
  +            fd = pollset->query_set[i].desc.s->socketdes;
  +        }
  +        else {
  +            fd = pollset->query_set[i].desc.f->filedes;
  +        }
  +        for (j = 0; j < rv; j++) {
  +            if (pollset->ke_set[j].ident == fd ) {
  +                pollset->result_set[r] = pollset->query_set[i];
  +                pollset->result_set[r].rtnevents =
  +                    get_kqueue_revent(pollset->ke_set[j].filter,
  +                                      pollset->ke_set[j].flags);
  +                r++;
  +            }
  +        }
  +    }
  +
  +    (*num) = r;
  +
  +    if (descriptors) {
  +        *descriptors = pollset->result_set;
  +    }
  +
  +    return APR_SUCCESS;
  +}
  +
  +#elif defined(HAVE_EPOLL)
  +
  +APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset,
  +                                           apr_interval_time_t timeout,
  +                                           apr_int32_t *num,
  +                                           const apr_pollfd_t **descriptors)
  +{
  +    int rv;
  +    apr_uint32_t i, j, k;
  +
  +    if (timeout > 0) {
  +        timeout /= 1000;
  +    }
  +
  +    rv = epoll_wait(pollset->epoll_fd, pollset->pollset, pollset->nelts,
  +                    timeout);
  +    (*num) = rv;
  +    if (rv < 0) {
  +        return apr_get_netos_error();
  +    }
  +    if (rv == 0) {
  +        return APR_TIMEUP;
  +    }
  +    j = 0;
  +    for (i = 0; i < pollset->nelts; i++) {
  +        if (pollset->pollset[i].events != 0) {
  +            /* TODO: Is there a better way to re-associate our data? */
  +            for (k = 0; k < pollset->nelts; k++) {
  +                if (pollset->query_set[k].desc_type == APR_POLL_SOCKET &&
  +                    pollset->query_set[k].desc.s->socketdes ==
  +                        pollset->pollset[i].data.fd) {
  +                    pollset->result_set[j] = pollset->query_set[k];
  +                    pollset->result_set[j].rtnevents =
  +                        get_epoll_revent(pollset->pollset[i].events);
  +                    j++;
  +                    break;
  +                }
  +                else if (pollset->query_set[k].desc_type == APR_POLL_FILE 
  +                         && pollset->query_set[k].desc.f->filedes ==
  +                            pollset->pollset[i].data.fd) {
  +                    pollset->result_set[j] = pollset->query_set[k];
  +                    pollset->result_set[j].rtnevents =
  +                        get_epoll_revent(pollset->pollset[i].events);
  +                    j++;
  +                    break;
  +                }
  +            }
  +        }
  +    }
  +    if (descriptors) {
  +        *descriptors = pollset->result_set;
  +    }
  +    return APR_SUCCESS;
  +}
  +#elif defined(HAVE_POLL)
   APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset,
                                              apr_interval_time_t timeout,
                                              apr_int32_t *num,
  
  
  
  1.34      +8 -4      apr/test/testpoll.c
  
  Index: testpoll.c
  ===================================================================
  RCS file: /home/cvs/apr/test/testpoll.c,v
  retrieving revision 1.33
  retrieving revision 1.34
  diff -u -u -r1.33 -r1.34
  --- testpoll.c	26 May 2004 14:50:27 -0000	1.33
  +++ testpoll.c	6 Jul 2004 03:38:06 -0000	1.34
  @@ -489,10 +489,14 @@
       rv = apr_pollset_poll(pollset, 1000, &num, &hot_files);
       ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
       ABTS_INT_EQUAL(tc, 2, num);
  -    ABTS_PTR_EQUAL(tc, (void *)1, hot_files[0].client_data);
  -    ABTS_PTR_EQUAL(tc, s[0], hot_files[0].desc.s);
  -    ABTS_PTR_EQUAL(tc, (void *)4, hot_files[1].client_data);
  -    ABTS_PTR_EQUAL(tc, s[3], hot_files[1].desc.s);
  +    ABTS_ASSERT(tc, "Incorrect socket in result set",
  +            ((hot_files[0].desc.s == s[0]) && (hot_files[1].desc.s == s[3]))  ||
  +            ((hot_files[0].desc.s == s[3]) && (hot_files[1].desc.s == s[0])));
  +    ABTS_ASSERT(tc, "Incorrect client data in result set",
  +            ((hot_files[0].client_data == (void *)1) &&
  +             (hot_files[1].client_data == (void *)4)) ||
  +            ((hot_files[0].client_data == (void *)4) &&
  +             (hot_files[1].client_data == (void *)1)));
   }
   
   abts_suite *testpoll(abts_suite *suite)
  
  
  

Mime
View raw message