[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