From 4f60044d29214728d1ef188977a9d013f623fb63 Mon Sep 17 00:00:00 2001 From: Kurt Zeilenga Date: Tue, 16 Mar 1999 23:33:30 +0000 Subject: [PATCH] First cut at bind race fix. Passes our test suite at least. --- servers/slapd/connection.c | 136 +++++++++++++++++++++++++++++-------- servers/slapd/operation.c | 78 ++++++++++++++------- servers/slapd/proto-slap.h | 9 ++- servers/slapd/slap.h | 2 +- 4 files changed, 167 insertions(+), 58 deletions(-) diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c index 7246a17b2f..7587147733 100644 --- a/servers/slapd/connection.c +++ b/servers/slapd/connection.c @@ -10,6 +10,9 @@ #include "slap.h" +static int connection_op_activate( Connection *conn, Operation *op ); +static int connection_resched( Connection *conn ); + struct co_arg { Connection *co_conn; Operation *co_op; @@ -25,59 +28,61 @@ static void * connection_operation( void *arg_v ) { struct co_arg *arg = arg_v; + int tag = arg->co_op->o_tag; + Connection *conn = arg->co_conn; - ldap_pvt_thread_mutex_lock( &arg->co_conn->c_opsmutex ); - arg->co_conn->c_ops_received++; - ldap_pvt_thread_mutex_unlock( &arg->co_conn->c_opsmutex ); + ldap_pvt_thread_mutex_lock( &conn->c_opsmutex ); + conn->c_ops_received++; + ldap_pvt_thread_mutex_unlock( &conn->c_opsmutex ); ldap_pvt_thread_mutex_lock( &ops_mutex ); ops_initiated++; ldap_pvt_thread_mutex_unlock( &ops_mutex ); - switch ( arg->co_op->o_tag ) { + switch ( tag ) { case LDAP_REQ_BIND: - do_bind( arg->co_conn, arg->co_op ); + do_bind( conn, arg->co_op ); break; #ifdef LDAP_COMPAT30 case LDAP_REQ_UNBIND_30: #endif case LDAP_REQ_UNBIND: - do_unbind( arg->co_conn, arg->co_op ); + do_unbind( conn, arg->co_op ); break; case LDAP_REQ_ADD: - do_add( arg->co_conn, arg->co_op ); + do_add( conn, arg->co_op ); break; #ifdef LDAP_COMPAT30 case LDAP_REQ_DELETE_30: #endif case LDAP_REQ_DELETE: - do_delete( arg->co_conn, arg->co_op ); + do_delete( conn, arg->co_op ); break; case LDAP_REQ_MODRDN: - do_modrdn( arg->co_conn, arg->co_op ); + do_modrdn( conn, arg->co_op ); break; case LDAP_REQ_MODIFY: - do_modify( arg->co_conn, arg->co_op ); + do_modify( conn, arg->co_op ); break; case LDAP_REQ_COMPARE: - do_compare( arg->co_conn, arg->co_op ); + do_compare( conn, arg->co_op ); break; case LDAP_REQ_SEARCH: - do_search( arg->co_conn, arg->co_op ); + do_search( conn, arg->co_op ); break; #ifdef LDAP_COMPAT30 case LDAP_REQ_ABANDON_30: #endif case LDAP_REQ_ABANDON: - do_abandon( arg->co_conn, arg->co_op ); + do_abandon( conn, arg->co_op ); break; default: @@ -86,20 +91,25 @@ connection_operation( void *arg_v ) break; } - ldap_pvt_thread_mutex_lock( &arg->co_conn->c_opsmutex ); - arg->co_conn->c_ops_completed++; - - slap_op_delete( &arg->co_conn->c_ops, arg->co_op ); - arg->co_op = NULL; + ldap_pvt_thread_mutex_lock( &ops_mutex ); + ops_completed++; + ldap_pvt_thread_mutex_unlock( &ops_mutex ); - ldap_pvt_thread_mutex_unlock( &arg->co_conn->c_opsmutex ); + ldap_pvt_thread_mutex_lock( &conn->c_opsmutex ); + conn->c_ops_completed++; + slap_op_remove( &conn->c_ops, arg->co_op ); + slap_op_free( arg->co_op ); + arg->co_op = NULL; arg->co_conn = NULL; free( (char *) arg ); + arg = NULL; - ldap_pvt_thread_mutex_lock( &ops_mutex ); - ops_completed++; - ldap_pvt_thread_mutex_unlock( &ops_mutex ); + if((tag == LDAP_REQ_BIND) && (conn->c_state == SLAP_C_BINDING)) { + conn->c_state = SLAP_C_ACTIVE; + } + + ldap_pvt_thread_mutex_unlock( &conn->c_opsmutex ); ldap_pvt_thread_mutex_lock( &active_threads_mutex ); active_threads--; @@ -107,6 +117,9 @@ connection_operation( void *arg_v ) ldap_pvt_thread_cond_signal(&active_threads_cond); } ldap_pvt_thread_mutex_unlock( &active_threads_mutex ); + + connection_resched( conn ); + return NULL; } @@ -115,12 +128,10 @@ connection_activity( Connection *conn ) { - int status; - struct co_arg *arg; + Operation *op; unsigned long tag, len; long msgid; BerElement *ber; - char *tmpdn; if ( conn->c_currentber == NULL && (conn->c_currentber = ber_alloc()) == NULL ) { @@ -178,8 +189,60 @@ connection_activity( } #endif - arg = (struct co_arg *) ch_malloc( sizeof(struct co_arg) ); - arg->co_conn = conn; + op = slap_op_alloc( ber, msgid, tag, + conn->c_ops_received, conn->c_connid ); + + if ( conn->c_state == SLAP_C_BINDING ) { + /* connection is binding to a dn, make 'em wait */ + ldap_pvt_thread_mutex_lock( &conn->c_opsmutex ); + slap_op_add( &conn->c_pending_ops, op ); + + Debug( LDAP_DEBUG_ANY, "deferring operation\n", 0, 0, 0 ); + + ldap_pvt_thread_mutex_unlock( &conn->c_opsmutex ); + + return; + } + + connection_op_activate( conn, op ); +} + +static int +connection_resched( Connection *conn ) +{ + Operation *op; + + if( conn->c_state != SLAP_C_ACTIVE ) { + /* other states need different handling */ + return; + } + + ldap_pvt_thread_mutex_lock( &conn->c_opsmutex ); + + for( op = slap_op_pop( &conn->c_pending_ops ); + op != NULL; + op = slap_op_pop( &conn->c_pending_ops ) ) + { + ldap_pvt_thread_mutex_unlock( &conn->c_opsmutex ); + + connection_op_activate( conn, op ); + + ldap_pvt_thread_mutex_lock( &conn->c_opsmutex ); + + if ( conn->c_state == SLAP_C_BINDING ) { + break; + } + } + + ldap_pvt_thread_mutex_unlock( &conn->c_opsmutex ); +} + +static int connection_op_activate( Connection *conn, Operation *op ) +{ + struct co_arg *arg; + char *tmpdn; + int status; + unsigned long tag = op->o_tag; ldap_pvt_thread_mutex_lock( &conn->c_dnmutex ); if ( conn->c_dn != NULL ) { @@ -189,9 +252,21 @@ connection_activity( } ldap_pvt_thread_mutex_unlock( &conn->c_dnmutex ); + arg = (struct co_arg *) ch_malloc( sizeof(struct co_arg) ); + arg->co_conn = conn; + arg->co_op = op; + + arg->co_op->o_dn = ch_strdup( tmpdn != NULL ? tmpdn : "" ); + arg->co_op->o_ndn = dn_normalize_case( ch_strdup( arg->co_op->o_dn ) ); + ldap_pvt_thread_mutex_lock( &conn->c_opsmutex ); - arg->co_op = slap_op_add( &conn->c_ops, ber, msgid, tag, tmpdn, - conn->c_ops_received, conn->c_connid ); + + slap_op_add( &conn->c_ops, arg->co_op ); + + if(tag == LDAP_REQ_BIND) { + conn->c_state = SLAP_C_BINDING; + } + ldap_pvt_thread_mutex_unlock( &conn->c_opsmutex ); if ( tmpdn != NULL ) { @@ -204,7 +279,10 @@ connection_activity( status = ldap_pvt_thread_create( &arg->co_op->o_tid, 1, connection_operation, (void *) arg ); + if ( status != 0 ) { Debug( LDAP_DEBUG_ANY, "ldap_pvt_thread_create failed (%d)\n", status, 0, 0 ); } + + return status; } diff --git a/servers/slapd/operation.c b/servers/slapd/operation.c index 2fff851887..404e20d888 100644 --- a/servers/slapd/operation.c +++ b/servers/slapd/operation.c @@ -13,6 +13,10 @@ void slap_op_free( Operation *op ) { +#ifdef LDAP_DEBUG + assert( op->o_next == NULL ); +#endif + ldap_pvt_thread_mutex_lock( &op->o_abandonmutex ); if ( op->o_ber != NULL ) { @@ -31,44 +35,54 @@ slap_op_free( Operation *op ) } Operation * -slap_op_add( - Operation **olist, +slap_op_alloc( BerElement *ber, unsigned long msgid, unsigned long tag, - char *dn, int id, int connid ) { - Operation **tmp; + Operation *op; - for ( tmp = olist; *tmp != NULL; tmp = &(*tmp)->o_next ) - ; /* NULL */ - - *tmp = (Operation *) ch_calloc( 1, sizeof(Operation) ); + op = (Operation *) ch_calloc( 1, sizeof(Operation) ); - ldap_pvt_thread_mutex_init( &(*tmp)->o_abandonmutex ); - (*tmp)->o_ber = ber; - (*tmp)->o_msgid = msgid; - (*tmp)->o_tag = tag; - (*tmp)->o_abandon = 0; + ldap_pvt_thread_mutex_init( &op->o_abandonmutex ); + op->o_ber = ber; + op->o_msgid = msgid; + op->o_tag = tag; + op->o_abandon = 0; - (*tmp)->o_dn = ch_strdup( dn != NULL ? dn : "" ); - (*tmp)->o_ndn = dn_normalize_case( ch_strdup( (*tmp)->o_dn ) ); + op->o_dn = NULL; + op->o_ndn = NULL; ldap_pvt_thread_mutex_lock( ¤ttime_mutex ); - (*tmp)->o_time = currenttime; + op->o_time = currenttime; ldap_pvt_thread_mutex_unlock( ¤ttime_mutex ); - (*tmp)->o_opid = id; - (*tmp)->o_connid = connid; - (*tmp)->o_next = NULL; + op->o_opid = id; + op->o_connid = connid; + op->o_next = NULL; - return( *tmp ); + return( op ); } -void -slap_op_delete( Operation **olist, Operation *op ) +int slap_op_add( + Operation **olist, + Operation *op +) +{ + Operation **tmp; + + for ( tmp = olist; *tmp != NULL; tmp = &(*tmp)->o_next ) + ; /* NULL */ + + *tmp = op; + + return 0; +} + +int +slap_op_remove( Operation **olist, Operation *op ) { Operation **tmp; @@ -78,10 +92,24 @@ slap_op_delete( Operation **olist, Operation *op ) if ( *tmp == NULL ) { Debug( LDAP_DEBUG_ANY, "op_delete: can't find op %ld\n", op->o_msgid, 0, 0 ); - slap_op_free( op ); - return; + return -1; } *tmp = (*tmp)->o_next; - slap_op_free( op ); + op->o_next = NULL; + + return 0; } + +Operation * slap_op_pop( Operation **olist ) +{ + Operation *tmp = *olist; + + if(tmp != NULL) { + *olist = tmp->o_next; + tmp->o_next = NULL; + } + + return tmp; +} + diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index b3b1a9737a..18fd25614b 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -171,10 +171,13 @@ void monitor_info LDAP_P(( Connection *conn, Operation *op )); */ void slap_op_free LDAP_P(( Operation *op )); -Operation * slap_op_add LDAP_P(( Operation **olist, +Operation * slap_op_alloc LDAP_P(( BerElement *ber, unsigned long msgid, - unsigned long tag, char *dn, int id, int connid )); -void slap_op_delete LDAP_P(( Operation **olist, Operation *op )); + unsigned long tag, int id, int connid )); + +int slap_op_add LDAP_P(( Operation **olist, Operation *op )); +int slap_op_remove LDAP_P(( Operation **olist, Operation *op )); +Operation * slap_op_pop LDAP_P(( Operation **olist )); /* * phonetic.c diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 3457eddc80..c9e9ad7338 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -399,7 +399,7 @@ typedef struct slap_op { struct sockaddr o_clientaddr; /* client address if via CLDAP */ char o_searchbase; /* search base if via CLDAP */ #endif - struct slap_op *o_next; /* next operation pending */ + struct slap_op *o_next; /* next operation in list */ ldap_pvt_thread_t o_tid; /* thread handling this op */ int o_abandon; /* signals op has been abandoned */ ldap_pvt_thread_mutex_t o_abandonmutex; /* signals op has been abandoned */ -- 2.39.5