summaryrefslogtreecommitdiff
path: root/poll/unix/port.c
diff options
context:
space:
mode:
authortrawick <trawick@13f79535-47bb-0310-9956-ffa450edef68>2009-08-24 15:02:05 +0000
committertrawick <trawick@13f79535-47bb-0310-9956-ffa450edef68>2009-08-24 15:02:05 +0000
commitab0485847353f61ba84a1137541186dcebfd7033 (patch)
treecca5ecd500a6813054dd6861aef587f2b6be4261 /poll/unix/port.c
parent7d49e130882987b094b69bed5f0ebec53a4d1369 (diff)
downloadlibapr-ab0485847353f61ba84a1137541186dcebfd7033.tar.gz
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
Diffstat (limited to 'poll/unix/port.c')
-rw-r--r--poll/unix/port.c112
1 files changed, 60 insertions, 52 deletions
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);