From ab0485847353f61ba84a1137541186dcebfd7033 Mon Sep 17 00:00:00 2001 From: trawick Date: Mon, 24 Aug 2009 15:02:05 +0000 Subject: Fix an error handling issue in the Event Port backend for APR pollsets. (ETIME is sometimes reported along with an event.) PR: 47645 git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@807263 13f79535-47bb-0310-9956-ffa450edef68 --- poll/unix/port.c | 112 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 60 insertions(+), 52 deletions(-) (limited to 'poll/unix/port.c') diff --git a/poll/unix/port.c b/poll/unix/port.c index 468131f4d..6e33196de 100644 --- a/poll/unix/port.c +++ b/poll/unix/port.c @@ -86,6 +86,58 @@ struct apr_pollset_private_t volatile apr_uint32_t waiting; }; +static apr_status_t call_port_getn(int port, port_event_t list[], + unsigned int max, unsigned int *nget, + apr_interval_time_t timeout) +{ + struct timespec tv, *tvptr; + int ret; + 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 = port_getn(port, list, max, nget, tvptr); + + if (ret < 0) { + rv = apr_get_netos_error(); + + switch(rv) { + case EINTR: + case ETIME: + if (*nget > 0) { + /* This confusing API can return an event at the same time + * that it reports EINTR or ETIME. If that occurs, just + * report the event. + * (Maybe it will be simplified; see thread + * http://mail.opensolaris.org + * /pipermail/networking-discuss/2009-August/011979.html + * This code will still work afterwards.) + */ + rv = APR_SUCCESS; + break; + } + if (rv == ETIME) { + rv = APR_TIMEUP; + } + /* fall-through */ + default: + *nget = 0; + } + } + else if (*nget == 0) { + rv = APR_TIMEUP; + } + + return rv; +} + static apr_status_t impl_pollset_cleanup(apr_pollset_t *pollset) { close(pollset->p->port_fd); @@ -288,19 +340,9 @@ static apr_status_t impl_pollset_poll(apr_pollset_t *pollset, int ret, i, j; unsigned int nget; pfd_elem_t *ep; - struct timespec tv, *tvptr; apr_status_t rv = APR_SUCCESS; apr_pollfd_t fp; - 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; - } - nget = 1; pollset_lock_rings(); @@ -337,27 +379,15 @@ static apr_status_t impl_pollset_poll(apr_pollset_t *pollset, return rv; } - ret = port_getn(pollset->p->port_fd, pollset->p->port_set, pollset->nalloc, - &nget, tvptr); + rv = call_port_getn(pollset->p->port_fd, pollset->p->port_set, + pollset->nalloc, &nget, timeout); /* decrease the waiting ASAP to reduce the window for calling port_associate within apr_pollset_add() */ apr_atomic_dec32(&pollset->p->waiting); - (*num) = nget; - if (ret == -1) { - (*num) = 0; - if (errno == ETIME) { - rv = APR_TIMEUP; - } - else { - rv = apr_get_netos_error(); - } - } - else if (nget == 0) { - rv = APR_TIMEUP; - } - else { + (*num) = nget; + if (nget) { pollset_lock_rings(); @@ -502,36 +532,14 @@ static apr_status_t impl_pollcb_poll(apr_pollcb_t *pollcb, apr_pollcb_cb_t func, void *baton) { - int ret; apr_pollfd_t *pollfd; - struct timespec tv, *tvptr; - apr_status_t rv = APR_SUCCESS; + apr_status_t rv; unsigned int i, nget = pollcb->nalloc; - 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; - } + rv = call_port_getn(pollcb->fd, pollcb->pollset.port, pollcb->nalloc, + &nget, timeout); - ret = port_getn(pollcb->fd, pollcb->pollset.port, pollcb->nalloc, - &nget, tvptr); - - if (ret == -1) { - if (errno == ETIME) { - rv = APR_TIMEUP; - } - else { - rv = apr_get_netos_error(); - } - } - else if (nget == 0) { - rv = APR_TIMEUP; - } - else { + if (nget) { for (i = 0; i < nget; i++) { pollfd = (apr_pollfd_t *)(pollcb->pollset.port[i].portev_user); pollfd->rtnevents = get_revent(pollcb->pollset.port[i].portev_events); -- cgit v1.2.1