Commit 4f60044d authored by Kurt Zeilenga's avatar Kurt Zeilenga
Browse files

First cut at bind race fix. Passes our test suite at least.

parent cc38cf65
......@@ -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;
}
......@@ -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( &currenttime_mutex );
(*tmp)->o_time = currenttime;
op->o_time = currenttime;
ldap_pvt_thread_mutex_unlock( &currenttime_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;
}
......@@ -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
......
......@@ -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 */
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment