#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;
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:
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--;
ldap_pvt_thread_cond_signal(&active_threads_cond);
}
ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
+
+ connection_resched( conn );
+
return NULL;
}
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 ) {
}
#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 ) {
}
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 ) {
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;
}
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 ) {
}
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;
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;
+}
+