Modify send_result to return if connection state is closing.
Modify do_abandon() to remove abandon'ed operation if pending.
{
int id;
Operation *o;
+ Operation **oo;
Debug( LDAP_DEBUG_TRACE, "do_abandon\n", 0, 0, 0 );
ldap_pvt_thread_mutex_lock( &conn->c_mutex );
for ( o = conn->c_ops; o != NULL; o = o->o_next ) {
- if ( o->o_msgid == id )
- goto found_op;
- }
- for ( o = conn->c_pending_ops; o != NULL; o = o->o_next ) {
- if ( o->o_msgid == id )
- break;
+ if ( o->o_msgid == id ) {
+ ldap_pvt_thread_mutex_lock( &o->o_abandonmutex );
+ o->o_abandon = 1;
+ ldap_pvt_thread_mutex_unlock( &o->o_abandonmutex );
+
+ goto found_it;
+ }
}
-found_op:
+ for ( oo = &conn->c_pending_ops;
+ (*oo != NULL) && ((*oo)->o_msgid != id);
+ oo = &(*oo)->o_next )
+ {
+ /* EMPTY */ ;
+ }
- if ( o != NULL ) {
- ldap_pvt_thread_mutex_lock( &o->o_abandonmutex );
- o->o_abandon = 1;
- ldap_pvt_thread_mutex_unlock( &o->o_abandonmutex );
+ if( *oo != NULL ) {
+ o = *oo;
+ *oo = (*oo)->o_next;
+ slap_op_free( o );
- } else {
- Debug( LDAP_DEBUG_TRACE, "do_abandon: op not found\n", 0, 0,
- 0 );
+ goto found_it;
}
+ Debug( LDAP_DEBUG_TRACE, "do_abandon: op not found\n", 0, 0, 0 );
+
+found_it:
ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
}
lber_pvt_sb_destroy( &c->c_sb );
}
+int connection_state_closing( Connection *c )
+{
+ assert( c != NULL );
+ assert( c->c_struct_state == SLAP_C_USED );
+ assert( c->c_conn_state != SLAP_C_INVALID );
+
+ return c->c_conn_state == SLAP_C_CLOSING;
+}
+
void connection_closing( Connection *c )
{
assert( connections != NULL );
assert( c->c_conn_state != SLAP_C_INVALID );
if( c->c_conn_state != SLAP_C_CLOSING ) {
+ Operation *o;
+
+ Debug( LDAP_DEBUG_TRACE,
+ "connection_closing: readying conn=%ld sd=%d for close.\n",
+ c->c_connid, c->c_sb.sb_sd, 0 );
+
/* don't listen on this port anymore */
slapd_clr_read( c->c_sb.sb_sd, 1 );
c->c_conn_state = SLAP_C_CLOSING;
+
+ /* shutdown I/O -- not yet implemented */
+
+ /* abandon active operations */
+ for( o = c->c_ops; o != NULL; o = o->o_next ) {
+ ldap_pvt_thread_mutex_lock( &o->o_abandonmutex );
+ o->o_abandon = 1;
+ ldap_pvt_thread_mutex_unlock( &o->o_abandonmutex );
+ }
+
+ /* remove pending operations */
+ for( o = slap_op_pop( &c->c_pending_ops );
+ o != NULL;
+ o = slap_op_pop( &c->c_pending_ops ) )
+ {
+ slap_op_free( o );
+ }
+
+ /* wake write blocked operations */
+ ldap_pvt_thread_cond_signal( &c->c_write_cv );
}
}
op != NULL;
op = slap_op_pop( &conn->c_pending_ops ) )
{
+ /* pending operations should not be marked for abandonment */
+ assert(!op->o_abandon);
+
connection_op_activate( conn, op );
if ( conn->c_conn_state == SLAP_C_BINDING ) {
const char* name, const char* addr));
void connection_closing LDAP_P(( Connection *c ));
+int connection_state_closing LDAP_P(( Connection *c ));
int connection_write LDAP_P((int s));
int connection_read LDAP_P((int s));
/* write the pdu */
bytes = ber->ber_ptr - ber->ber_buf;
- while ( ber_flush( &conn->c_sb, ber, 1 ) != 0 ) {
- int err = errno;
+ while ( 1 ) {
+ int err;
+
+ if ( connection_state_closing( conn ) ) {
+ ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
+ ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
+ return;
+ }
+
+ if ( ber_flush( &conn->c_sb, ber, 1 ) == 0 ) {
+ break;
+ }
+
+ err = errno;
+
/*
* we got an error. if it's ewouldblock, we need to
* wait on the socket being writable. otherwise, figure
ldap_pvt_thread_mutex_lock( &conn->c_mutex );
/* write the pdu */
- while ( ber_flush( &conn->c_sb, ber, 1 ) != 0 ) {
- int err = errno;
+ while( 1 ) {
+ int err;
+
+ if ( connection_state_closing( conn ) ) {
+ ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
+ ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
+ return;
+ }
+
+ if ( ber_flush( &conn->c_sb, ber, 1 ) == 0 ) {
+ break;
+ }
+
+ err = errno;
+
/*
* we got an error. if it's ewouldblock, we need to
* wait on the socket being writable. otherwise, figure