mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-12-27 18:19:52 -05:00
First cut at bind race fix. Passes our test suite at least.
This commit is contained in:
parent
cc38cf6534
commit
4f60044d29
4 changed files with 170 additions and 61 deletions
|
|
@ -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,27 +91,35 @@ 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_unlock( &arg->co_conn->c_opsmutex );
|
||||
|
||||
arg->co_conn = NULL;
|
||||
free( (char *) arg );
|
||||
|
||||
ldap_pvt_thread_mutex_lock( &ops_mutex );
|
||||
ops_completed++;
|
||||
ldap_pvt_thread_mutex_unlock( &ops_mutex );
|
||||
|
||||
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;
|
||||
|
||||
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--;
|
||||
if( active_threads < 1 ) {
|
||||
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 *op;
|
||||
|
||||
op = (Operation *) ch_calloc( 1, sizeof(Operation) );
|
||||
|
||||
ldap_pvt_thread_mutex_init( &op->o_abandonmutex );
|
||||
op->o_ber = ber;
|
||||
op->o_msgid = msgid;
|
||||
op->o_tag = tag;
|
||||
op->o_abandon = 0;
|
||||
|
||||
op->o_dn = NULL;
|
||||
op->o_ndn = NULL;
|
||||
|
||||
ldap_pvt_thread_mutex_lock( ¤ttime_mutex );
|
||||
op->o_time = currenttime;
|
||||
ldap_pvt_thread_mutex_unlock( ¤ttime_mutex );
|
||||
op->o_opid = id;
|
||||
op->o_connid = connid;
|
||||
op->o_next = NULL;
|
||||
|
||||
return( op );
|
||||
}
|
||||
|
||||
int slap_op_add(
|
||||
Operation **olist,
|
||||
Operation *op
|
||||
)
|
||||
{
|
||||
Operation **tmp;
|
||||
|
||||
for ( tmp = olist; *tmp != NULL; tmp = &(*tmp)->o_next )
|
||||
; /* NULL */
|
||||
|
||||
*tmp = (Operation *) ch_calloc( 1, sizeof(Operation) );
|
||||
*tmp = op;
|
||||
|
||||
ldap_pvt_thread_mutex_init( &(*tmp)->o_abandonmutex );
|
||||
(*tmp)->o_ber = ber;
|
||||
(*tmp)->o_msgid = msgid;
|
||||
(*tmp)->o_tag = tag;
|
||||
(*tmp)->o_abandon = 0;
|
||||
|
||||
(*tmp)->o_dn = ch_strdup( dn != NULL ? dn : "" );
|
||||
(*tmp)->o_ndn = dn_normalize_case( ch_strdup( (*tmp)->o_dn ) );
|
||||
|
||||
ldap_pvt_thread_mutex_lock( ¤ttime_mutex );
|
||||
(*tmp)->o_time = currenttime;
|
||||
ldap_pvt_thread_mutex_unlock( ¤ttime_mutex );
|
||||
(*tmp)->o_opid = id;
|
||||
(*tmp)->o_connid = connid;
|
||||
(*tmp)->o_next = NULL;
|
||||
|
||||
return( *tmp );
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
slap_op_delete( Operation **olist, Operation *op )
|
||||
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 */
|
||||
|
|
|
|||
Loading…
Reference in a new issue