diff options
author | trawick <trawick@13f79535-47bb-0310-9956-ffa450edef68> | 2009-08-24 15:03:57 +0000 |
---|---|---|
committer | trawick <trawick@13f79535-47bb-0310-9956-ffa450edef68> | 2009-08-24 15:03:57 +0000 |
commit | c93beb0fd300abb9699c136d73519a62bded1e1f (patch) | |
tree | fdb50436c8b30ac08dde9342a83dc7f77e4fb8ef /poll | |
parent | 4918152cecd1d54c8c2ee528e94d876e27939faf (diff) | |
download | libapr-c93beb0fd300abb9699c136d73519a62bded1e1f.tar.gz |
backport r807263 from trunk:
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/branches/1.4.x@807265 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'poll')
-rw-r--r-- | poll/unix/port.c | 112 |
1 files changed, 60 insertions, 52 deletions
diff --git a/poll/unix/port.c b/poll/unix/port.c index f7fd03bb1..c5d98749e 100644 --- a/poll/unix/port.c +++ b/poll/unix/port.c @@ -85,6 +85,58 @@ struct apr_pollset_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 backend_cleanup(void *p_) { apr_pollset_t *pollset = (apr_pollset_t *) p_; @@ -337,19 +389,9 @@ APR_DECLARE(apr_status_t) apr_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(); @@ -385,27 +427,15 @@ APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset, return rv; } - ret = port_getn(pollset->port_fd, pollset->port_set, pollset->nalloc, - &nget, tvptr); + rv = call_port_getn(pollset->port_fd, pollset->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->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(); @@ -554,36 +584,14 @@ APR_DECLARE(apr_status_t) apr_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->port_fd, pollcb->port_set, pollcb->nalloc, + &nget, timeout); - ret = port_getn(pollcb->port_fd, pollcb->port_set, 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->port_set[i].portev_user); pollfd->rtnevents = get_revent(pollcb->port_set[i].portev_events); |