Author: rjung Date: Sat May 23 11:17:11 2015 New Revision: 1681321 URL: http://svn.apache.org/r1681321 Log: Forward port 1.1 changes to trunk:
r1518225 | schultz | 2013-08-28 16:52:00 +0200 (Wed, 28 Aug 2013) | 4 lines Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=51813 Add NULL-checking for s->net to avoid SIGSEGV in situations where it appears a socket has been recycled. r1412919 | mturk | 2012-11-23 16:44:27 +0100 (Fri, 23 Nov 2012) | 1 line Use apr_ring instead array for maintaining pollset r1411077 | mturk | 2012-11-19 07:38:06 +0100 (Mon, 19 Nov 2012) | 1 line Preformance tuning. Use APR_POLLSET_NOCOPY since we always have allocated sockets and we depend on apr-1.3.x as minimum version Modified: tomcat/native/trunk/native/include/tcn.h tomcat/native/trunk/native/src/network.c tomcat/native/trunk/native/src/poll.c Modified: tomcat/native/trunk/native/include/tcn.h URL: http://svn.apache.org/viewvc/tomcat/native/trunk/native/include/tcn.h?rev=1681321&r1=1681320&r2=1681321&view=diff ============================================================================== --- tomcat/native/trunk/native/include/tcn.h (original) +++ tomcat/native/trunk/native/include/tcn.h Sat May 23 11:17:11 2015 @@ -23,6 +23,8 @@ #include "apr_pools.h" #include "apr_portable.h" #include "apr_network_io.h" +#include "apr_poll.h" +#include "apr_ring.h" #include "apr_strings.h" #ifndef APR_HAS_THREADS @@ -138,7 +140,15 @@ typedef struct { apr_status_t (APR_THREAD_FUNC *recv) (apr_socket_t *, char *, apr_size_t *); } tcn_nlayer_t; -typedef struct { +typedef struct tcn_socket_t tcn_socket_t; +typedef struct tcn_pfde_t tcn_pfde_t; + +struct tcn_pfde_t { + APR_RING_ENTRY(tcn_pfde_t) link; + apr_pollfd_t fd; +}; + +struct tcn_socket_t { apr_pool_t *pool; apr_pool_t *child; apr_socket_t *sock; @@ -148,7 +158,7 @@ typedef struct { tcn_nlayer_t *net; apr_time_t last_active; apr_interval_time_t timeout; -} tcn_socket_t; +}; /* Private helper functions */ void tcn_Throw(JNIEnv *, const char *, ...); Modified: tomcat/native/trunk/native/src/network.c URL: http://svn.apache.org/viewvc/tomcat/native/trunk/native/src/network.c?rev=1681321&r1=1681320&r2=1681321&view=diff ============================================================================== --- tomcat/native/trunk/native/src/network.c (original) +++ tomcat/native/trunk/native/src/network.c Sat May 23 11:17:11 2015 @@ -203,8 +203,7 @@ TCN_IMPLEMENT_CALL(jlong, Socket, create a->sock = s; if (family >= 0) a->net = &apr_socket_layer; - a->opaque = s; - + a->opaque = s; return P2J(a); cleanup: if (c) @@ -434,6 +433,10 @@ TCN_IMPLEMENT_CALL(jint, Socket, send)(T return -(jint)APR_ENOTSOCK; } TCN_ASSERT(s->opaque != NULL); + if(!s->net) { + tcn_ThrowAPRException(e, APR_EINVALSOCK); + return -(jint)APR_EINVALSOCK; + } #ifdef TCN_DO_STATISTICS sp_max_send = TCN_MAX(sp_max_send, nbytes); sp_min_send = TCN_MIN(sp_min_send, nbytes); @@ -510,6 +513,10 @@ TCN_IMPLEMENT_CALL(jint, Socket, sendb)( } TCN_ASSERT(s->opaque != NULL); TCN_ASSERT(buf != NULL); + if(!s->net) { + tcn_ThrowAPRException(e, APR_EINVALSOCK); + return -(jint)APR_EINVALSOCK; + } #ifdef TCN_DO_STATISTICS sp_max_send = TCN_MAX(sp_max_send, nbytes); sp_min_send = TCN_MIN(sp_min_send, nbytes); @@ -550,6 +557,10 @@ TCN_IMPLEMENT_CALL(jint, Socket, sendib) } TCN_ASSERT(s->opaque != NULL); TCN_ASSERT(buf != NULL); + if(!s->net) { + tcn_ThrowAPRException(e, APR_EINVALSOCK); + return -(jint)APR_EINVALSOCK; + } #ifdef TCN_DO_STATISTICS sp_max_send = TCN_MAX(sp_max_send, nbytes); sp_min_send = TCN_MIN(sp_min_send, nbytes); @@ -584,6 +595,10 @@ TCN_IMPLEMENT_CALL(jint, Socket, sendbb) } TCN_ASSERT(s->opaque != NULL); TCN_ASSERT(s->jsbbuff != NULL); + if(!s->net) { + tcn_ThrowAPRException(e, APR_EINVALSOCK); + return -(jint)APR_EINVALSOCK; + } #ifdef TCN_DO_STATISTICS sp_max_send = TCN_MAX(sp_max_send, nbytes); sp_min_send = TCN_MIN(sp_min_send, nbytes); @@ -620,6 +635,10 @@ TCN_IMPLEMENT_CALL(jint, Socket, sendibb } TCN_ASSERT(s->opaque != NULL); TCN_ASSERT(s->jsbbuff != NULL); + if(!s->net) { + tcn_ThrowAPRException(e, APR_EINVALSOCK); + return -(jint)APR_EINVALSOCK; + } #ifdef TCN_DO_STATISTICS sp_max_send = TCN_MAX(sp_max_send, nbytes); sp_min_send = TCN_MIN(sp_min_send, nbytes); @@ -651,6 +670,10 @@ TCN_IMPLEMENT_CALL(jint, Socket, sendv)( UNREFERENCED(o); TCN_ASSERT(sock != 0); TCN_ASSERT(s->opaque != NULL); + if(!s->net) { + tcn_ThrowAPRException(e, APR_EINVALSOCK); + return -(jint)APR_EINVALSOCK; + } nvec = (*e)->GetArrayLength(e, bufs); if (nvec >= APR_MAX_IOVEC_SIZE) @@ -720,6 +743,10 @@ TCN_IMPLEMENT_CALL(jint, Socket, recv)(T UNREFERENCED(o); TCN_ASSERT(sock != 0); TCN_ASSERT(s->opaque != NULL); + if(!s->net) { + tcn_ThrowAPRException(e, APR_EINVALSOCK); + return -(jint)APR_EINVALSOCK; + } if (toread <= TCN_BUFFER_SZ) { char sb[TCN_BUFFER_SZ]; @@ -779,6 +806,10 @@ TCN_IMPLEMENT_CALL(jint, Socket, recvt)( TCN_ASSERT(sock != 0); TCN_ASSERT(s->opaque != NULL); TCN_ASSERT(buf != NULL); + if(!s->net) { + tcn_ThrowAPRException(e, APR_EINVALSOCK); + return -(jint)APR_EINVALSOCK; + } if ((ss = (*s->net->timeout_get)(s->opaque, &pt)) != APR_SUCCESS) { TCN_ERROR_WRAP(ss); @@ -851,6 +882,10 @@ TCN_IMPLEMENT_CALL(jint, Socket, recvb)( } TCN_ASSERT(s->opaque != NULL); TCN_ASSERT(buf != NULL); + if(!s->net) { + tcn_ThrowAPRException(e, APR_EINVALSOCK); + return -(jint)APR_EINVALSOCK; + } bytes = (char *)(*e)->GetDirectBufferAddress(e, buf); TCN_ASSERT(bytes != NULL); @@ -899,6 +934,10 @@ TCN_IMPLEMENT_CALL(jint, Socket, recvbb) TCN_ASSERT(sock != 0); TCN_ASSERT(s->opaque != NULL); TCN_ASSERT(s->jrbbuff != NULL); + if(!s->net) { + tcn_ThrowAPRException(e, APR_EINVALSOCK); + return -(jint)APR_EINVALSOCK; + } ss = (*s->net->recv)(s->opaque, s->jrbbuff + offset, &nbytes); #ifdef TCN_DO_STATISTICS @@ -950,6 +989,10 @@ TCN_IMPLEMENT_CALL(jint, Socket, recvbt) } TCN_ASSERT(buf != NULL); TCN_ASSERT(s->opaque != NULL); + if(!s->net) { + tcn_ThrowAPRException(e, APR_EINVALSOCK); + return -(jint)APR_EINVALSOCK; + } bytes = (char *)(*e)->GetDirectBufferAddress(e, buf); TCN_ASSERT(bytes != NULL); @@ -1019,7 +1062,10 @@ TCN_IMPLEMENT_CALL(jint, Socket, recvbbt } TCN_ASSERT(s->jrbbuff != NULL); TCN_ASSERT(s->opaque != NULL); - + if(!s->net) { + tcn_ThrowAPRException(e, APR_EINVALSOCK); + return -(jint)APR_EINVALSOCK; + } if ((ss = (*s->net->timeout_get)(s->opaque, &pt)) != APR_SUCCESS) { TCN_ERROR_WRAP(ss); Modified: tomcat/native/trunk/native/src/poll.c URL: http://svn.apache.org/viewvc/tomcat/native/trunk/native/src/poll.c?rev=1681321&r1=1681320&r2=1681321&view=diff ============================================================================== --- tomcat/native/trunk/native/src/poll.c (original) +++ tomcat/native/trunk/native/src/poll.c Sat May 23 11:17:11 2015 @@ -15,8 +15,6 @@ */ #include "tcn.h" -#include "apr_poll.h" - #ifdef TCN_DO_STATISTICS static int sp_created = 0; @@ -26,16 +24,24 @@ static int sp_cleared = 0; /* Internal poll structure for queryset */ - typedef struct tcn_pollset { apr_pool_t *pool; apr_int32_t nelts; apr_int32_t nalloc; apr_pollset_t *pollset; jlong *set; - apr_pollfd_t *socket_set; apr_interval_time_t default_timeout; jboolean wakeable; + /* A ring containing all of the pollfd_t that are active + */ + APR_RING_HEAD(pfd_poll_ring_t, tcn_pfde_t) poll_ring; + /* A ring of pollfd_t that have been used, and then _remove()'d + */ + APR_RING_HEAD(pfd_free_ring_t, tcn_pfde_t) free_ring; + /* A ring of pollfd_t where rings that have been _remove()`ed but + * might still be inside a _poll() + */ + APR_RING_HEAD(pfd_dead_ring_t, tcn_pfde_t) dead_ring; #ifdef TCN_DO_STATISTICS int sp_added; int sp_max_count; @@ -98,7 +104,7 @@ TCN_IMPLEMENT_CALL(jlong, Poll, create)( apr_pool_t *p = J2P(pool, apr_pool_t *); apr_pollset_t *pollset = NULL; tcn_pollset_t *tps = NULL; - apr_uint32_t f = (apr_uint32_t)flags; + apr_uint32_t f = (apr_uint32_t)flags | APR_POLLSET_NOCOPY; UNREFERENCED(o); TCN_ASSERT(pool != 0); @@ -155,10 +161,12 @@ TCN_IMPLEMENT_CALL(jlong, Poll, create)( tps = apr_pcalloc(p, sizeof(tcn_pollset_t)); TCN_CHECK_ALLOCATED(tps); tps->pollset = pollset; - tps->set = apr_palloc(p, size * sizeof(jlong) * 2); + tps->set = apr_pcalloc(p, size * sizeof(jlong) * 2); TCN_CHECK_ALLOCATED(tps->set); - tps->socket_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); - TCN_CHECK_ALLOCATED(tps->socket_set); + APR_RING_INIT(&tps->poll_ring, tcn_pfde_t, link); + APR_RING_INIT(&tps->free_ring, tcn_pfde_t, link); + APR_RING_INIT(&tps->dead_ring, tcn_pfde_t, link); + tps->nelts = 0; tps->nalloc = size; tps->pool = p; @@ -195,10 +203,12 @@ TCN_IMPLEMENT_CALL(jint, Poll, destroy)( static apr_status_t do_add(tcn_pollset_t *p, tcn_socket_t *s, apr_int16_t reqevents, - apr_interval_time_t socket_timeout) { + apr_interval_time_t socket_timeout) +{ + apr_status_t rv; apr_interval_time_t timeout = socket_timeout; - apr_pollfd_t fd; + tcn_pfde_t *elem = NULL; if (p->nelts == p->nalloc) { #ifdef TCN_DO_STATISTICS @@ -214,20 +224,30 @@ static apr_status_t do_add(tcn_pollset_t else s->last_active = 0; s->timeout = socket_timeout; - - memset(&fd, 0, sizeof(apr_pollfd_t)); - fd.desc_type = APR_POLL_SOCKET; - fd.reqevents = reqevents; - fd.desc.s = s->sock; - fd.client_data = s; - - p->socket_set[p->nelts] = fd; - p->nelts++; + if (!APR_RING_EMPTY(&p->free_ring, tcn_pfde_t, link)) { + elem = APR_RING_FIRST(&p->free_ring); + APR_RING_REMOVE(elem, link); + } + else { + elem = (tcn_pfde_t *)apr_palloc(p->pool, sizeof(tcn_pfde_t)); + APR_RING_ELEM_INIT(elem, link); + } + elem->fd.reqevents = reqevents; + elem->fd.desc_type = APR_POLL_SOCKET; + elem->fd.desc.s = s->sock; + elem->fd.client_data = s; #ifdef TCN_DO_STATISTICS p->sp_added++; p->sp_max_count = TCN_MAX(p->sp_max_count, p->sp_added); #endif - return (jint)apr_pollset_add(p->pollset, &fd); + rv = apr_pollset_add(p->pollset, &elem->fd); + if (rv != APR_SUCCESS) { + APR_RING_INSERT_TAIL(&p->free_ring, elem, tcn_pfde_t, link); + } + else { + APR_RING_INSERT_TAIL(&p->poll_ring, elem, tcn_pfde_t, link); + } + return rv; } TCN_IMPLEMENT_CALL(jint, Poll, add)(TCN_STDARGS, jlong pollset, @@ -257,46 +277,33 @@ TCN_IMPLEMENT_CALL(jint, Poll, addWithTi static apr_status_t do_remove(tcn_pollset_t *p, const apr_pollfd_t *fd) { - apr_int32_t i; + apr_status_t rv; + tcn_pfde_t *ep; - for (i = 0; i < p->nelts; i++) { - if (fd->desc.s == p->socket_set[i].desc.s) { - /* Found an instance of the fd: remove this and any other copies */ - apr_int32_t dst = i; - apr_int32_t old_nelts = p->nelts; - tcn_socket_t *ds = (tcn_socket_t *)p->socket_set[dst].client_data; + rv = apr_pollset_remove(p->pollset, fd); + APR_RING_FOREACH(ep, &p->poll_ring, tcn_pfde_t, link) + { + if (fd->desc.s == ep->fd.desc.s) { + APR_RING_REMOVE(ep, link); + APR_RING_INSERT_TAIL(&p->dead_ring, ep, tcn_pfde_t, link); p->nelts--; #ifdef TCN_DO_STATISTICS p->sp_removed++; #endif - for (i++; i < old_nelts; i++) { - tcn_socket_t *ss = (tcn_socket_t *)p->socket_set[i].client_data; - if (fd->desc.s == p->socket_set[i].desc.s) { -#ifdef TCN_DO_STATISTICS - p->sp_equals++; -#endif - p->nelts--; - } - else { - p->socket_set[dst] = p->socket_set[i]; - ds->last_active = ss->last_active; - ds->timeout = ss->timeout; - ds = (tcn_socket_t *)p->socket_set[++dst].client_data; - } - } break; } } - return apr_pollset_remove(p->pollset, fd); + return rv; } static void update_last_active(tcn_pollset_t *p, const apr_pollfd_t *fd, apr_time_t t) { - apr_int32_t i; + tcn_pfde_t *ep; - for (i = 0; i < p->nelts; i++) { - if (fd->desc.s == p->socket_set[i].desc.s) { - tcn_socket_t *s = (tcn_socket_t *)p->socket_set[i].client_data; + APR_RING_FOREACH(ep, &p->poll_ring, tcn_pfde_t, link) + { + if (fd->desc.s == ep->fd.desc.s) { + tcn_socket_t *s = (tcn_socket_t *)ep->fd.client_data; /* Found an instance of the fd: update last active time */ s->last_active = t; break; @@ -307,17 +314,17 @@ static void update_last_active(tcn_polls TCN_IMPLEMENT_CALL(jint, Poll, remove)(TCN_STDARGS, jlong pollset, jlong socket) { + apr_pollfd_t fd; tcn_pollset_t *p = J2P(pollset, tcn_pollset_t *); tcn_socket_t *s = J2P(socket, tcn_socket_t *); - apr_pollfd_t fd; UNREFERENCED_STDARGS; TCN_ASSERT(socket != 0); - memset(&fd, 0, sizeof(apr_pollfd_t)); - fd.desc_type = APR_POLL_SOCKET; - fd.desc.s = s->sock; - fd.reqevents = APR_POLLIN | APR_POLLOUT; + fd.desc_type = APR_POLL_SOCKET; + fd.desc.s = s->sock; + fd.client_data = s; + fd.reqevents = APR_POLLIN | APR_POLLOUT; #ifdef TCN_DO_STATISTICS p->sp_remove++; #endif @@ -344,12 +351,15 @@ TCN_IMPLEMENT_CALL(jint, Poll, poll)(TCN #endif if (ptime > 0) { - now = apr_time_now(); + tcn_pfde_t *ep; + now = apr_time_now(); /* Find the minimum timeout */ - for (i = 0; i < p->nelts; i++) { + APR_RING_FOREACH(ep, &p->poll_ring, tcn_pfde_t, link) + { apr_interval_time_t socket_timeout = 0; - tcn_socket_t *s = (tcn_socket_t *)p->socket_set[i].client_data; + tcn_socket_t *s; + s = (tcn_socket_t *)ep->fd.client_data; if (s->timeout == TCN_NO_SOCKET_TIMEOUT) { socket_timeout = p->default_timeout; } @@ -390,6 +400,8 @@ TCN_IMPLEMENT_CALL(jint, Poll, poll)(TCN } break; } + /* Shift all PFDs in the Dead Ring to the Free Ring */ + APR_RING_CONCAT(&p->free_ring, &p->dead_ring, tcn_pfde_t, link); if (num > 0) { #ifdef TCN_DO_STATISTICS p->sp_polled += num; @@ -418,15 +430,16 @@ TCN_IMPLEMENT_CALL(jint, Poll, maintain) tcn_pollset_t *p = J2P(pollset, tcn_pollset_t *); apr_int32_t i = 0, num = 0; apr_time_t now = apr_time_now(); - apr_pollfd_t fd; + tcn_pfde_t *ep, *ip; UNREFERENCED(o); TCN_ASSERT(pollset != 0); /* Check for timeout sockets */ - for (i = 0; i < p->nelts; i++) { + APR_RING_FOREACH_SAFE(ep, ip, &p->poll_ring, tcn_pfde_t, link) + { apr_interval_time_t timeout = 0; - tcn_socket_t *s = (tcn_socket_t *)p->socket_set[i].client_data; + tcn_socket_t *s = (tcn_socket_t *)ep->fd.client_data; if (s->timeout == TCN_NO_SOCKET_TIMEOUT) { timeout = p->default_timeout; } @@ -438,19 +451,27 @@ TCN_IMPLEMENT_CALL(jint, Poll, maintain) } if ((now - s->last_active) >= timeout) { p->set[num++] = P2J(s); + APR_RING_REMOVE(ep, link); + APR_RING_INSERT_TAIL(&p->dead_ring, ep, tcn_pfde_t, link); + p->nelts--; +#ifdef TCN_DO_STATISTICS + p->sp_removed++; +#endif } } if (remove && num) { - memset(&fd, 0, sizeof(apr_pollfd_t)); #ifdef TCN_DO_STATISTICS p->sp_maintained += num; p->sp_max_maintained = TCN_MAX(p->sp_max_maintained, num); #endif for (i = 0; i < num; i++) { - fd.desc_type = APR_POLL_SOCKET; - fd.reqevents = APR_POLLIN | APR_POLLOUT; - fd.desc.s = (J2P(p->set[i], tcn_socket_t *))->sock; - do_remove(p, &fd); + apr_pollfd_t fd; + tcn_socket_t *s = J2P(p->set[i], tcn_socket_t *); + fd.desc_type = APR_POLL_SOCKET; + fd.desc.s = s->sock; + fd.client_data = s; + fd.reqevents = APR_POLLIN | APR_POLLOUT; + apr_pollset_remove(p->pollset, &fd); } } if (num) @@ -477,21 +498,22 @@ TCN_IMPLEMENT_CALL(jint, Poll, pollset)( jlongArray set) { tcn_pollset_t *p = J2P(pollset, tcn_pollset_t *); - apr_int32_t i = 0; - apr_pollfd_t fd; + apr_int32_t n = 0; + tcn_pfde_t *ep; UNREFERENCED(o); TCN_ASSERT(pollset != 0); - for (i = 0; i < p->nelts; i++) { - p->socket_set[i].rtnevents = APR_POLLHUP | APR_POLLIN; - fd = p->socket_set[i]; - p->set[i*2+0] = (jlong)(fd.rtnevents); - p->set[i*2+1] = P2J(fd.client_data); - } - if (p->nelts) - (*e)->SetLongArrayRegion(e, set, 0, p->nelts * 2, p->set); - return (jint)p->nelts; + APR_RING_FOREACH(ep, &p->poll_ring, tcn_pfde_t, link) + { + apr_pollfd_t *fd = &ep->fd; + fd->rtnevents = APR_POLLHUP | APR_POLLIN; + p->set[n++] = (jlong)(fd->rtnevents); + p->set[n++] = P2J(fd->client_data); + } + if (n > 0) + (*e)->SetLongArrayRegion(e, set, 0, n, p->set); + return n; } TCN_IMPLEMENT_CALL(jboolean, Poll, wakeable)(TCN_STDARGS, jlong pollset) --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org