You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@apr.apache.org by tr...@apache.org on 2009/03/06 02:38:58 UTC
svn commit: r750744 - in /apr/apr/trunk:
include/arch/unix/apr_arch_poll_private.h poll/unix/port.c
Author: trawick
Date: Fri Mar 6 01:38:58 2009
New Revision: 750744
URL: http://svn.apache.org/viewvc?rev=750744&view=rev
Log:
fix a race condition between pollset_poll and pollset_remove
T1: port_getn called from pollset_poll
T2: pollset_remove called for fd X
T2: obtains ring lock
T1: port_getn returns event for fd X, kernel disassociates from port
T1: blocks on ring lock
T2: moves ring element for fd X from query ring to dead ring
T2: releases ring lock
T1: obtains ring lock
T1: moves ring element for fd X to add ring, assuming still on query ring
Modified:
apr/apr/trunk/include/arch/unix/apr_arch_poll_private.h
apr/apr/trunk/poll/unix/port.c
Modified: apr/apr/trunk/include/arch/unix/apr_arch_poll_private.h
URL: http://svn.apache.org/viewvc/apr/apr/trunk/include/arch/unix/apr_arch_poll_private.h?rev=750744&r1=750743&r2=750744&view=diff
==============================================================================
--- apr/apr/trunk/include/arch/unix/apr_arch_poll_private.h (original)
+++ apr/apr/trunk/include/arch/unix/apr_arch_poll_private.h Fri Mar 6 01:38:58 2009
@@ -97,6 +97,9 @@
struct pfd_elem_t {
APR_RING_ENTRY(pfd_elem_t) link;
apr_pollfd_t pfd;
+#ifdef HAVE_PORT_CREATE
+ int on_query_ring;
+#endif
};
#endif
Modified: apr/apr/trunk/poll/unix/port.c
URL: http://svn.apache.org/viewvc/apr/apr/trunk/poll/unix/port.c?rev=750744&r1=750743&r2=750744&view=diff
==============================================================================
--- apr/apr/trunk/poll/unix/port.c (original)
+++ apr/apr/trunk/poll/unix/port.c Fri Mar 6 01:38:58 2009
@@ -162,6 +162,7 @@
else {
elem = (pfd_elem_t *) apr_palloc(pollset->pool, sizeof(pfd_elem_t));
APR_RING_ELEM_INIT(elem, link);
+ elem->on_query_ring = 0;
}
elem->pfd = *descriptor;
@@ -185,6 +186,7 @@
}
else {
pollset->nelts++;
+ elem->on_query_ring = 1;
APR_RING_INSERT_TAIL(&(pollset->p->query_ring), elem, pfd_elem_t, link);
}
}
@@ -246,6 +248,12 @@
res = port_dissociate(pollset->p->port_fd, PORT_SOURCE_FD, fd);
if (res < 0) {
+ /* The expected case for this failure is that another
+ * thread's call to port_getn() returned this fd and
+ * disassociated the fd from the event port, and
+ * impl_pollset_poll() is blocked on the ring lock,
+ * which this thread holds.
+ */
err = errno;
rv = APR_NOTFOUND;
}
@@ -257,6 +265,7 @@
if (descriptor->desc.s == ep->pfd.desc.s) {
APR_RING_REMOVE(ep, link);
+ ep->on_query_ring = 0;
APR_RING_INSERT_TAIL(&(pollset->p->dead_ring),
ep, pfd_elem_t, link);
if (ENOENT == err) {
@@ -319,6 +328,7 @@
break;
}
+ ep->on_query_ring = 1;
APR_RING_INSERT_TAIL(&(pollset->p->query_ring), ep, pfd_elem_t, link);
}
@@ -366,11 +376,18 @@
pollset->p->result_set[j].rtnevents =
get_revent(pollset->p->port_set[i].portev_events);
- APR_RING_REMOVE((pfd_elem_t*)pollset->p->port_set[i].portev_user,
- link);
- APR_RING_INSERT_TAIL(&(pollset->p->add_ring),
- (pfd_elem_t*)pollset->p->port_set[i].portev_user,
- pfd_elem_t, link);
+ /* If the ring element is still on the query ring, move it
+ * to the add ring for re-association with the event port
+ * later. (It may have already been moved to the dead ring
+ * by a call to pollset_remove on another thread.)
+ */
+ ep = (pfd_elem_t *)pollset->p->port_set[i].portev_user;
+ if (ep->on_query_ring) {
+ APR_RING_REMOVE(ep, link);
+ ep->on_query_ring = 0;
+ APR_RING_INSERT_TAIL(&(pollset->p->add_ring), ep,
+ pfd_elem_t, link);
+ }
j++;
}
}