]> git.sur5r.net Git - openldap/commitdiff
ITS#5835 fix connection teradown when there are waiting writers
authorHoward Chu <hyc@openldap.org>
Thu, 15 Jan 2009 20:41:40 +0000 (20:41 +0000)
committerHoward Chu <hyc@openldap.org>
Thu, 15 Jan 2009 20:41:40 +0000 (20:41 +0000)
servers/slapd/connection.c
servers/slapd/result.c
servers/slapd/slap.h
servers/slapd/slapi/slapi_ops.c

index 179025a9f0e9fd8a3d63e4643d04982cf1b4ddb7..f20a0552b487ffd142a6989e9f52a6dbd0f38e69 100644 (file)
@@ -163,8 +163,10 @@ int connections_destroy(void)
                if( connections[i].c_struct_state != SLAP_C_UNINITIALIZED ) {
                        ber_sockbuf_free( connections[i].c_sb );
                        ldap_pvt_thread_mutex_destroy( &connections[i].c_mutex );
-                       ldap_pvt_thread_mutex_destroy( &connections[i].c_write_mutex );
-                       ldap_pvt_thread_cond_destroy( &connections[i].c_write_cv );
+                       ldap_pvt_thread_mutex_destroy( &connections[i].c_write1_mutex );
+                       ldap_pvt_thread_mutex_destroy( &connections[i].c_write2_mutex );
+                       ldap_pvt_thread_cond_destroy( &connections[i].c_write1_cv );
+                       ldap_pvt_thread_cond_destroy( &connections[i].c_write2_cv );
 #ifdef LDAP_SLAPI
                        if ( slapi_plugins_used ) {
                                slapi_int_free_object_extensions( SLAPI_X_EXT_CONNECTION,
@@ -387,8 +389,10 @@ Connection * connection_init(
 
                /* should check status of thread calls */
                ldap_pvt_thread_mutex_init( &c->c_mutex );
-               ldap_pvt_thread_mutex_init( &c->c_write_mutex );
-               ldap_pvt_thread_cond_init( &c->c_write_cv );
+               ldap_pvt_thread_mutex_init( &c->c_write1_mutex );
+               ldap_pvt_thread_mutex_init( &c->c_write2_mutex );
+               ldap_pvt_thread_cond_init( &c->c_write1_cv );
+               ldap_pvt_thread_cond_init( &c->c_write2_cv );
 
 #ifdef LDAP_SLAPI
                if ( slapi_plugins_used ) {
@@ -420,6 +424,7 @@ Connection * connection_init(
        assert( c->c_sasl_bindop == NULL );
        assert( c->c_currentber == NULL );
        assert( c->c_writewaiter == 0);
+       assert( c->c_writers == 0);
 
        c->c_listener = listener;
        c->c_sd = s;
@@ -596,6 +601,7 @@ connection_destroy( Connection *c )
        assert( LDAP_STAILQ_EMPTY(&c->c_txn_ops) );
 #endif
        assert( c->c_writewaiter == 0);
+       assert( c->c_writers == 0);
 
        /* only for stats (print -1 as "%lu" may give unexpected results ;) */
        connid = c->c_connid;
@@ -755,17 +761,22 @@ void connection_closing( Connection *c, const char *why )
                connection_abandon( c );
 
                /* wake write blocked operations */
-               if ( c->c_writewaiter ) {
-                       ldap_pvt_thread_cond_signal( &c->c_write_cv );
-                       /* ITS#4667 this may allow another thread to drop into
-                        * connection_resched / connection_close before we
-                        * finish, but that's OK.
-                        */
-                       slapd_clr_write( c->c_sd, 1 );
-                       ldap_pvt_thread_mutex_unlock( &c->c_mutex );
-                       ldap_pvt_thread_mutex_lock( &c->c_write_mutex );
-                       ldap_pvt_thread_mutex_lock( &c->c_mutex );
-                       ldap_pvt_thread_mutex_unlock( &c->c_write_mutex );
+               if ( c->c_writers > 0 ) {
+                       ldap_pvt_thread_mutex_lock( &c->c_write1_mutex );
+                       c->c_writers = -c->c_writers;
+                       ldap_pvt_thread_cond_broadcast( &c->c_write1_cv );
+                       ldap_pvt_thread_mutex_unlock( &c->c_write1_mutex );
+                       if ( c->c_writewaiter ) {
+                               ldap_pvt_thread_mutex_lock( &c->c_write2_mutex );
+                               ldap_pvt_thread_cond_signal( &c->c_write2_cv );
+                               slapd_clr_write( c->c_sd, 1 );
+                               ldap_pvt_thread_mutex_unlock( &c->c_write2_mutex );
+                       }
+                       ldap_pvt_thread_mutex_lock( &c->c_write1_mutex );
+                       while ( c->c_writers ) {
+                               ldap_pvt_thread_cond_wait( &c->c_write1_cv, &c->c_write1_mutex );
+                       }
+                       ldap_pvt_thread_mutex_unlock( &c->c_write1_mutex );
                } else {
                        slapd_clr_write( c->c_sd, 1 );
                }
@@ -781,11 +792,6 @@ connection_close( Connection *c )
 {
        assert( connections != NULL );
        assert( c != NULL );
-
-       /* ITS#4667 we may have gotten here twice */
-       if ( c->c_conn_state == SLAP_C_INVALID )
-               return;
-
        assert( c->c_struct_state == SLAP_C_USED );
        assert( c->c_conn_state == SLAP_C_CLOSING );
 
@@ -1249,7 +1255,6 @@ int connection_read_activate( ber_socket_t s )
        return rc;
 }
 
-/* Used for epoll / event functions that distinguish hangups from read events */
 void
 connection_hangup( ber_socket_t s )
 {
@@ -1848,7 +1853,7 @@ int connection_write(ber_socket_t s)
        Debug( LDAP_DEBUG_TRACE,
                "connection_write(%d): waking output for id=%lu\n",
                s, c->c_connid, 0 );
-       ldap_pvt_thread_cond_signal( &c->c_write_cv );
+       ldap_pvt_thread_cond_signal( &c->c_write2_cv );
 
        if ( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_NEEDS_READ, NULL ) ) {
                slapd_set_read( s, 1 );
index a2e7343eb6ceca4568d990848114e4a317525405..b5c6b90f5f3d5086c0ca1f93e39692d49acf4de1 100644 (file)
@@ -137,27 +137,40 @@ static long send_ldap_ber(
        BerElement *ber )
 {
        ber_len_t bytes;
+       long ret = 0;
+       int closing = 0;
 
        ber_get_option( ber, LBER_OPT_BER_BYTES_TO_WRITE, &bytes );
 
        /* write only one pdu at a time - wait til it's our turn */
-       ldap_pvt_thread_mutex_lock( &conn->c_write_mutex );
+       ldap_pvt_thread_mutex_lock( &conn->c_write1_mutex );
+       while ( conn->c_writers > 0 ) {
+               ldap_pvt_thread_cond_wait( &conn->c_write1_cv, &conn->c_write1_mutex );
+       }
+       /* connection was closed under us */
+       if ( conn->c_writers < 0 ) {
+               closing = 1;
+               /* we're the last waiter, let the closer continue */
+               if ( conn->c_writers == -1 )
+                       ldap_pvt_thread_cond_signal( &conn->c_write1_cv );
+       }
 
-       /* lock the connection */ 
-       ldap_pvt_thread_mutex_lock( &conn->c_mutex );
+       conn->c_writers++;
+       ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex );
+
+       if ( closing )
+               return 0;
 
        /* write the pdu */
        while( 1 ) {
                int err;
 
-               if ( connection_state_closing( conn ) ) {
-                       ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
-                       ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
-
-                       return 0;
-               }
+               /* lock the connection */ 
+               ldap_pvt_thread_mutex_lock( &conn->c_mutex );
 
                if ( ber_flush2( conn->c_sb, ber, LBER_FLUSH_FREE_NEVER ) == 0 ) {
+                       ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
+                       ret = bytes;
                        break;
                }
 
@@ -176,23 +189,41 @@ static long send_ldap_ber(
                        connection_closing( conn, "connection lost on write" );
 
                        ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
-                       ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
 
-                       return( -1 );
+                       ret = -1;
+                       break;
                }
 
                /* wait for socket to be write-ready */
+               ldap_pvt_thread_mutex_lock( &conn->c_write2_mutex );
                conn->c_writewaiter = 1;
                slapd_set_write( conn->c_sd, 1 );
 
-               ldap_pvt_thread_cond_wait( &conn->c_write_cv, &conn->c_mutex );
+               ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
+               ldap_pvt_thread_cond_wait( &conn->c_write2_cv, &conn->c_write2_mutex );
                conn->c_writewaiter = 0;
+               ldap_pvt_thread_mutex_unlock( &conn->c_write2_mutex );
+               ldap_pvt_thread_mutex_lock( &conn->c_write1_mutex );
+               closing = ( conn->c_writers < 0 );
+               ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex );
+               if ( closing ) {
+                       ret = 0;
+                       break;
+               }
        }
 
-       ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
-       ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
+       ldap_pvt_thread_mutex_lock( &conn->c_write1_mutex );
+       if ( conn->c_writers < 0 ) {
+               conn->c_writers++;
+               if ( !conn->c_writers )
+                       ldap_pvt_thread_cond_signal( &conn->c_write1_cv );
+       } else {
+               conn->c_writers--;
+               ldap_pvt_thread_cond_signal( &conn->c_write1_cv );
+       }
+       ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex );
 
-       return bytes;
+       return ret;
 }
 
 static int
index dadd88d5c92db7cc444587eeb1c056e5d29f7468..b4e50e39123094c08e7a4f01222d2da3f55aa77c 100644 (file)
@@ -2801,14 +2801,17 @@ struct Connection {
        LDAP_STAILQ_HEAD(c_o, Operation) c_ops; /* list of operations being processed */
        LDAP_STAILQ_HEAD(c_po, Operation) c_pending_ops;        /* list of pending operations */
 
-       ldap_pvt_thread_mutex_t c_write_mutex;  /* only one pdu written at a time */
-       ldap_pvt_thread_cond_t  c_write_cv;             /* used to wait for sd write-ready*/
+       ldap_pvt_thread_mutex_t c_write1_mutex; /* only one pdu written at a time */
+       ldap_pvt_thread_cond_t  c_write1_cv;    /* only one pdu written at a time */
+       ldap_pvt_thread_mutex_t c_write2_mutex; /* used to wait for sd write-ready */
+       ldap_pvt_thread_cond_t  c_write2_cv;    /* used to wait for sd write-ready*/
 
        BerElement      *c_currentber;  /* ber we're attempting to read */
+       int                     c_writers;              /* number of writers waiting */
 
        char            c_sasl_bind_in_progress;        /* multi-op bind in progress */
+       char            c_writewaiter;  /* true if blocked on write */
 
-       char            c_writewaiter;  /* true if writer is waiting */
 
 #define        CONN_IS_TLS     1
 #define        CONN_IS_UDP     2
index e7aab5d8d370532d92b2ed06f8a443c49777ef85..eaf4060b01739d929894a98c9ac0191b9a3bf269 100644 (file)
@@ -224,8 +224,10 @@ slapi_int_connection_init_pb( Slapi_PBlock *pb, ber_tag_t tag )
 
        /* should check status of thread calls */
        ldap_pvt_thread_mutex_init( &conn->c_mutex );
-       ldap_pvt_thread_mutex_init( &conn->c_write_mutex );
-       ldap_pvt_thread_cond_init( &conn->c_write_cv );
+       ldap_pvt_thread_mutex_init( &conn->c_write1_mutex );
+       ldap_pvt_thread_mutex_init( &conn->c_write2_mutex );
+       ldap_pvt_thread_cond_init( &conn->c_write1_cv );
+       ldap_pvt_thread_cond_init( &conn->c_write2_cv );
 
        ldap_pvt_thread_mutex_lock( &conn->c_mutex );