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

Reply via email to