Skip to content
Snippets Groups Projects
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
No related branches found
No related tags found
No related merge requests found
......@@ -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 */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment