[prev in list] [next in list] [prev in thread] [next in thread] 

List:       apr-cvs
Subject:    svn commit: r509038 - in /apr/apr/trunk: CHANGES include/apr_poll.h
From:       pquerna () apache ! org
Date:       2007-02-19 0:31:02
Message-ID: 20070219003102.C47E01A981A () eris ! apache ! org
[Download RAW message or body]

Author: pquerna
Date: Sun Feb 18 16:31:01 2007
New Revision: 509038

URL: http://svn.apache.org/viewvc?view=rev&rev=509038
Log:
Add the apr_pollcb API.

This mostly sitting in the pollcb-dev branch for several months at:
   <https://svn.apache.org/repos/asf/apr/apr/branches/pollcb-dev/>

The version in this commit has small improvements, and an KQueue backend.

This will likely break trunk for operating systems were we only have select|poll, so \
we will need to add some autoconf foo to define a HAVE_APR_POLLCB unless someone can \
implement apr_pollcb for all platforms.

Modified:
    apr/apr/trunk/CHANGES
    apr/apr/trunk/include/apr_poll.h
    apr/apr/trunk/poll/unix/epoll.c
    apr/apr/trunk/poll/unix/kqueue.c
    apr/apr/trunk/test/testpoll.c

Modified: apr/apr/trunk/CHANGES
URL: http://svn.apache.org/viewvc/apr/apr/trunk/CHANGES?view=diff&rev=509038&r1=509037&r2=509038
 ==============================================================================
--- apr/apr/trunk/CHANGES (original)
+++ apr/apr/trunk/CHANGES Sun Feb 18 16:31:01 2007
@@ -1,5 +1,8 @@
 Changes for APR 1.3.0
 
+  *) Add the apr_pollcb API as an alternative more efficient method
+     of polling sockets, compared to apr_pollset. [Paul Querna]
+
   *) Fix possible crash in apr_pool_initialize() when built with 
      verbose pool debugging.  PR 41063.  
      [Peter Steiner <peter.steiner+apache hugwi.ch>]

Modified: apr/apr/trunk/include/apr_poll.h
URL: http://svn.apache.org/viewvc/apr/apr/trunk/include/apr_poll.h?view=diff&rev=509038&r1=509037&r2=509038
 ==============================================================================
--- apr/apr/trunk/include/apr_poll.h (original)
+++ apr/apr/trunk/include/apr_poll.h Sun Feb 18 16:31:01 2007
@@ -188,7 +188,27 @@
 
 /** @} */
 
+/** Opaque structure used for pollset API */
+typedef struct apr_pollcb_t apr_pollcb_t;
 
+APR_DECLARE(apr_status_t) apr_pollcb_create(apr_pollcb_t **pollcb,
+                                            apr_uint32_t size,
+                                            apr_pool_t *pool,
+                                            apr_uint32_t flags);
+
+
+APR_DECLARE(apr_status_t) apr_pollcb_add(apr_pollcb_t *pollcb,
+                                         apr_pollfd_t *descriptor);
+
+APR_DECLARE(apr_status_t) apr_pollcb_remove(apr_pollcb_t *pollcb,
+                                            apr_pollfd_t *descriptor);
+
+typedef apr_status_t(*apr_pollcb_cb_t)(void* baton, apr_pollfd_t *descriptor);
+
+APR_DECLARE(apr_status_t) apr_pollcb_poll(apr_pollcb_t *pollcb,
+                                          apr_interval_time_t timeout,
+                                          apr_pollcb_cb_t func,
+                                          void *baton); 
 #ifdef __cplusplus
 }
 #endif

Modified: apr/apr/trunk/poll/unix/epoll.c
URL: http://svn.apache.org/viewvc/apr/apr/trunk/poll/unix/epoll.c?view=diff&rev=509038&r1=509037&r2=509038
 ==============================================================================
--- apr/apr/trunk/poll/unix/epoll.c (original)
+++ apr/apr/trunk/poll/unix/epoll.c Sun Feb 18 16:31:01 2007
@@ -296,4 +296,128 @@
     return rv;
 }
 
+struct apr_pollcb_t {
+    apr_pool_t *pool;
+    apr_uint32_t nalloc;
+    struct epoll_event *pollset;
+    int epoll_fd;
+};
+
+static apr_status_t cb_cleanup(void *p_)
+{
+    apr_pollcb_t *pollcb = (apr_pollcb_t *) p_;
+    close(pollcb->epoll_fd);
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_pollcb_create(apr_pollcb_t **pollcb,
+                                            apr_uint32_t size,
+                                            apr_pool_t *p,
+                                            apr_uint32_t flags)
+{
+    int fd;
+    
+    fd = epoll_create(size);
+    
+    if (fd < 0) {
+        *pollcb = NULL;
+        return apr_get_netos_error();
+    }
+    
+    *pollcb = apr_palloc(p, sizeof(**pollcb));
+    (*pollcb)->nalloc = size;
+    (*pollcb)->pool = p;
+    (*pollcb)->epoll_fd = fd;
+    (*pollcb)->pollset = apr_palloc(p, size * sizeof(struct epoll_event));
+    apr_pool_cleanup_register(p, *pollcb, cb_cleanup, cb_cleanup);
+
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_pollcb_add(apr_pollcb_t *pollcb,
+                                         apr_pollfd_t *descriptor)
+{
+    struct epoll_event ev;
+    int ret;
+    
+    ev.events = get_epoll_event(descriptor->reqevents);
+    ev.data.ptr = (void *)descriptor;
+
+    if (descriptor->desc_type == APR_POLL_SOCKET) {
+        ret = epoll_ctl(pollcb->epoll_fd, EPOLL_CTL_ADD,
+                        descriptor->desc.s->socketdes, &ev);
+    }
+    else {
+        ret = epoll_ctl(pollcb->epoll_fd, EPOLL_CTL_ADD,
+                        descriptor->desc.f->filedes, &ev);
+    }
+    
+    if (ret == -1) {
+        return apr_get_netos_error();
+    }
+    
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_pollcb_remove(apr_pollcb_t *pollcb,
+                                            apr_pollfd_t *descriptor)
+{
+    apr_status_t rv = APR_SUCCESS;
+    struct epoll_event ev;
+    int ret = -1;
+    
+    ev.events = get_epoll_event(descriptor->reqevents);
+    
+    if (descriptor->desc_type == APR_POLL_SOCKET) {
+        ret = epoll_ctl(pollcb->epoll_fd, EPOLL_CTL_DEL,
+                        descriptor->desc.s->socketdes, &ev);
+    }
+    else {
+        ret = epoll_ctl(pollcb->epoll_fd, EPOLL_CTL_DEL,
+                        descriptor->desc.f->filedes, &ev);
+    }
+    
+    if (ret < 0) {
+        rv = APR_NOTFOUND;
+    }
+    
+    return rv;
+}
+
+
+APR_DECLARE(apr_status_t) apr_pollcb_poll(apr_pollcb_t *pollcb,
+                                          apr_interval_time_t timeout,
+                                          apr_pollcb_cb_t func,
+                                          void *baton)
+{
+    int ret, i;
+    apr_status_t rv = APR_SUCCESS;
+    
+    if (timeout > 0) {
+        timeout /= 1000;
+    }
+    
+    ret = epoll_wait(pollcb->epoll_fd, pollcb->pollset, pollcb->nalloc,
+                     timeout);
+    if (ret < 0) {
+        rv = apr_get_netos_error();
+    }
+    else if (ret == 0) {
+        rv = APR_TIMEUP;
+    }
+    else {
+        for (i = 0; i < ret; i++) {
+            apr_pollfd_t *pollfd = (apr_pollfd_t *)(pollcb->pollset[i].data.ptr);
+            pollfd->rtnevents = get_epoll_revent(pollcb->pollset[i].events);
+
+            rv = func(baton, pollfd);
+            if (rv) {
+                return rv;
+            }
+        }
+    }
+    
+    return rv;
+}
+
 #endif /* POLLSET_USES_EPOLL */

Modified: apr/apr/trunk/poll/unix/kqueue.c
URL: http://svn.apache.org/viewvc/apr/apr/trunk/poll/unix/kqueue.c?view=diff&rev=509038&r1=509037&r2=509038
 ==============================================================================
--- apr/apr/trunk/poll/unix/kqueue.c (original)
+++ apr/apr/trunk/poll/unix/kqueue.c Sun Feb 18 16:31:01 2007
@@ -281,4 +281,158 @@
     return rv;
 }
 
+
+struct apr_pollcb_t {
+    apr_pool_t *pool;
+    apr_uint32_t nalloc;
+    struct kevent *pollset;
+    int kqfd;
+};
+
+static apr_status_t cb_cleanup(void *b_)
+{
+    apr_pollcb_t *pollcb = (apr_pollcb_t *) b_;
+    close(pollcb->kqfd);
+    return APR_SUCCESS;
+}
+
+
+APR_DECLARE(apr_status_t) apr_pollcb_create(apr_pollcb_t **pollcb,
+                                            apr_uint32_t size,
+                                            apr_pool_t *p,
+                                            apr_uint32_t flags)
+{
+    int fd;
+    
+    fd = kqueue();
+    if (fd < 0) {
+        *pollcb = NULL;
+        return apr_get_netos_error();
+    }
+    
+    *pollcb = apr_palloc(p, sizeof(**pollcb));
+    (*pollcb)->nalloc = size;
+    (*pollcb)->pool = p;
+    (*pollcb)->kqfd = fd;
+    (*pollcb)->pollset = (struct kevent *)apr_pcalloc(p, size * sizeof(struct \
kevent)); +    apr_pool_cleanup_register(p, *pollcb, cb_cleanup, cb_cleanup);
+    
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_pollcb_add(apr_pollcb_t *pollcb,
+                                         apr_pollfd_t *descriptor)
+{
+    apr_os_sock_t fd;
+    struct kevent ev;
+    apr_status_t rv = APR_SUCCESS;
+    
+    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(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, descriptor);
+        
+        if (kevent(pollcb->kqfd, &ev, 1, NULL, 0, NULL) == -1) {
+            rv = apr_get_netos_error();
+        }
+    }
+    
+    if (descriptor->reqevents & APR_POLLOUT && rv == APR_SUCCESS) {
+        EV_SET(&ev, fd, EVFILT_WRITE, EV_ADD, 0, 0, descriptor);
+        
+        if (kevent(pollcb->kqfd, &ev, 1, NULL, 0, NULL) == -1) {
+            rv = apr_get_netos_error();
+        }
+    }
+    
+    return rv;
+}
+
+APR_DECLARE(apr_status_t) apr_pollcb_remove(apr_pollcb_t *pollcb,
+                                            apr_pollfd_t *descriptor)
+{
+    apr_status_t rv = APR_SUCCESS;
+    struct kevent ev;
+    apr_os_sock_t fd;
+    
+    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(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
+        
+        if (kevent(pollcb->kqfd, &ev, 1, NULL, 0, NULL) == -1) {
+            rv = APR_NOTFOUND;
+        }
+    }
+    
+    if (descriptor->reqevents & APR_POLLOUT && rv == APR_SUCCESS) {
+        /* XXXX: this is less than optimal, shouldn't we still try to 
+         *        remove the FD even if it wasn't in the readset?
+         */
+        EV_SET(&ev, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
+        
+        if (kevent(pollcb->kqfd, &ev, 1, NULL, 0, NULL) == -1) {
+            rv = APR_NOTFOUND;
+        }
+    }
+    
+    return rv;
+}
+
+
+APR_DECLARE(apr_status_t) apr_pollcb_poll(apr_pollcb_t *pollcb,
+                                          apr_interval_time_t timeout,
+                                          apr_pollcb_cb_t func,
+                                          void *baton)
+{
+    int ret, i;
+    struct timespec tv, *tvptr;
+    apr_status_t rv = APR_SUCCESS;
+    
+    if (timeout < 0) {
+        tvptr = NULL;
+    }
+    else {
+        tv.tv_sec = (long) apr_time_sec(timeout);
+        tv.tv_nsec = (long) apr_time_usec(timeout) * 1000;
+        tvptr = &tv;
+    }
+    
+    ret = kevent(pollcb->kqfd, NULL, 0, pollcb->pollset, pollcb->nalloc,
+                 tvptr);
+
+    if (ret < 0) {
+        rv = apr_get_netos_error();
+    }
+    else if (ret == 0) {
+        rv = APR_TIMEUP;
+    }
+    else {
+        for (i = 0; i < ret; i++) {
+            apr_pollfd_t *pollfd = (apr_pollfd_t *)(pollcb->pollset[i].udata);
+            
+            pollfd->rtnevents = get_kqueue_revent(pollcb->pollset[i].filter,
+                                                  pollcb->pollset[i].flags);
+            
+            rv = func(baton, pollfd);
+            
+            if (rv) {
+                return rv;
+            }
+        }
+    }
+
+    return rv;
+}
+
 #endif /* POLLSET_USES_KQUEUE */

Modified: apr/apr/trunk/test/testpoll.c
URL: http://svn.apache.org/viewvc/apr/apr/trunk/test/testpoll.c?view=diff&rev=509038&r1=509037&r2=509038
 ==============================================================================
--- apr/apr/trunk/test/testpoll.c (original)
+++ apr/apr/trunk/test/testpoll.c Sun Feb 18 16:31:01 2007
@@ -32,6 +32,7 @@
 static apr_socket_t *s[LARGE_NUM_SOCKETS];
 static apr_sockaddr_t *sa[LARGE_NUM_SOCKETS];
 static apr_pollset_t *pollset;
+static apr_pollcb_t *pollcb;
 
 /* ###: tests surrounded by ifdef OLD_POLL_INTERFACE either need to be
  * converted to use the pollset interface or removed. */
@@ -552,6 +553,91 @@
              (hot_files[1].client_data == (void *)1)));
 }
 
+static void setup_pollcb(abts_case *tc, void *data)
+{
+    apr_status_t rv;
+    rv = apr_pollcb_create(&pollcb, LARGE_NUM_SOCKETS, p, 0);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+}
+
+typedef struct pollcb_baton_t {
+    abts_case *tc;
+    int count;
+} pollcb_baton_t;
+
+static apr_status_t trigger_pollcb_cb(void* baton, apr_pollfd_t *descriptor)
+{
+    pollcb_baton_t* pcb = (pollcb_baton_t*) baton;
+    ABTS_PTR_EQUAL(pcb->tc, s[0], descriptor->desc.s);
+    ABTS_PTR_EQUAL(pcb->tc, s[0], descriptor->client_data);
+    pcb->count++;
+    return APR_SUCCESS;
+}
+
+static void trigger_pollcb(abts_case *tc, void *data)
+{
+    apr_status_t rv;
+    apr_pollfd_t socket_pollfd;
+    pollcb_baton_t pcb;
+    
+    ABTS_PTR_NOTNULL(tc, s[0]);
+    socket_pollfd.desc_type = APR_POLL_SOCKET;
+    socket_pollfd.reqevents = APR_POLLIN;
+    socket_pollfd.desc.s = s[0];
+    socket_pollfd.client_data = s[0];
+    rv = apr_pollcb_add(pollcb, &socket_pollfd);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+    
+    send_msg(s, sa, 0, tc);
+    pcb.tc = tc;
+    pcb.count = 0;
+    rv = apr_pollcb_poll(pollcb, 0, trigger_pollcb_cb, &pcb);    
+    ABTS_INT_EQUAL(tc, 0, APR_STATUS_IS_TIMEUP(rv));
+    ABTS_INT_EQUAL(tc, 1, pcb.count);
+
+    rv = apr_pollcb_remove(pollcb, &socket_pollfd);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+}
+
+static void timeout_pollcb(abts_case *tc, void *data)
+{
+    apr_status_t rv;
+    pollcb_baton_t pcb;
+    pcb.count = 0;
+    pcb.tc = tc;
+
+    rv = apr_pollcb_poll(pollcb, 1, trigger_pollcb_cb, &pcb);    
+    ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv));
+    ABTS_INT_EQUAL(tc, 0, pcb.count);
+}
+
+static void timeout_pollin_pollcb(abts_case *tc, void *data)
+{
+    apr_status_t rv;
+    pollcb_baton_t pcb;
+    apr_pollfd_t socket_pollfd;
+
+    recv_msg(s, 0, p, tc);
+    
+    ABTS_PTR_NOTNULL(tc, s[0]);
+    socket_pollfd.desc_type = APR_POLL_SOCKET;
+    socket_pollfd.reqevents = APR_POLLIN;
+    socket_pollfd.desc.s = s[0];
+    socket_pollfd.client_data = s[0];
+    rv = apr_pollcb_add(pollcb, &socket_pollfd);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+    
+    pcb.count = 0;
+    pcb.tc = tc;
+    
+    rv = apr_pollcb_poll(pollcb, 1, trigger_pollcb_cb, &pcb);    
+    ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv));
+    ABTS_INT_EQUAL(tc, 0, pcb.count);
+
+    rv = apr_pollcb_remove(pollcb, &socket_pollfd);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+}
+
 abts_suite *testpoll(abts_suite *suite)
 {
     suite = ADD_SUITE(suite)
@@ -584,6 +670,13 @@
 
     abts_run_test(suite, pollset_remove, NULL);
     
+    abts_run_test(suite, close_all_sockets, NULL);
+
+    abts_run_test(suite, create_all_sockets, NULL);
+    abts_run_test(suite, setup_pollcb, NULL);
+    abts_run_test(suite, trigger_pollcb, NULL);
+    abts_run_test(suite, timeout_pollcb, NULL);
+    abts_run_test(suite, timeout_pollin_pollcb, NULL);
     abts_run_test(suite, close_all_sockets, NULL);
 
     return suite;


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic