--- libraries/libldap/result.c 2011/01/04 23:50:04 1.124.2.28 +++ libraries/libldap/result.c 2011/01/06 18:43:21 1.124.2.29 @@ -1,5 +1,5 @@ /* result.c - wait for an ldap result */ -/* $OpenLDAP: pkg/ldap/libraries/libldap/result.c,v 1.124.2.27 2011/01/04 16:40:41 quanah Exp $ */ +/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2011 The OpenLDAP Foundation. @@ -66,8 +66,8 @@ #include "ldap_log.h" #include "lutil.h" -static int ldap_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid, int *idx )); -static int ldap_mark_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid, int idx )); +static int ldap_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid )); +static int ldap_mark_abandoned LDAP_P(( LDAP *ld, ber_int_t msgid )); static int wait4msg LDAP_P(( LDAP *ld, ber_int_t msgid, int all, struct timeval *timeout, LDAPMessage **result )); static ber_tag_t try_read1msg LDAP_P(( LDAP *ld, ber_int_t msgid, @@ -120,6 +120,7 @@ ldap_result( return rc; } +/* protected by res_mutex */ static LDAPMessage * chkResponseList( LDAP *ld, @@ -144,12 +145,10 @@ chkResponseList( lastlm = &ld->ld_responses; for ( lm = ld->ld_responses; lm != NULL; lm = nextlm ) { - int idx; - nextlm = lm->lm_next; ++cnt; - if ( ldap_abandoned( ld, lm->lm_msgid, &idx ) ) { + if ( ldap_abandoned( ld, lm->lm_msgid ) ) { Debug( LDAP_DEBUG_ANY, "response list msg abandoned, " "msgid %d message type %s\n", @@ -164,7 +163,7 @@ chkResponseList( default: /* there's no need to keep the id * in the abandoned list any longer */ - ldap_mark_abandoned( ld, lm->lm_msgid, idx ); + ldap_mark_abandoned( ld, lm->lm_msgid ); break; } @@ -231,6 +230,7 @@ chkResponseList( return lm; } +/* protected by res_mutex */ static int wait4msg( LDAP *ld, @@ -284,9 +284,7 @@ wait4msg( if ( ldap_debug & LDAP_DEBUG_TRACE ) { Debug( LDAP_DEBUG_TRACE, "wait4msg continue ld %p msgid %d all %d\n", (void *)ld, msgid, all ); - LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); ldap_dump_connection( ld, ld->ld_conns, 1 ); - LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); ldap_dump_requests_and_responses( ld ); LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); @@ -308,7 +306,6 @@ wait4msg( break; } } - LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); if ( !lc_ready ) { int err; @@ -328,6 +325,7 @@ wait4msg( { ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN : LDAP_TIMEOUT); + LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); return( rc ); } @@ -349,8 +347,6 @@ wait4msg( { ldap_int_flush_request( ld, ld->ld_requests ); } - LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); - LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); for ( lc = ld->ld_conns; rc == LDAP_MSG_X_KEEP_LOOKING && lc != NULL; lc = lnext ) @@ -360,25 +356,22 @@ wait4msg( { /* Don't let it get freed out from under us */ ++lc->lconn_refcnt; - LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); rc = try_read1msg( ld, msgid, all, lc, result ); lnext = lc->lconn_next; /* Only take locks if we're really freeing */ if ( lc->lconn_refcnt <= 1 ) { - LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); ldap_free_connection( ld, lc, 0, 1 ); - LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); } else { --lc->lconn_refcnt; } - LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); } else { lnext = lc->lconn_next; } } - LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); + LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); } + LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); } if ( rc == LDAP_MSG_X_KEEP_LOOKING && tvp != NULL ) { @@ -432,6 +425,7 @@ wait4msg( } +/* protected by res_mutex, conn_mutex and req_mutex */ static ber_tag_t try_read1msg( LDAP *ld, @@ -443,7 +437,6 @@ try_read1msg( BerElement *ber; LDAPMessage *newmsg, *l, *prev; ber_int_t id; - int idx; ber_tag_t tag; ber_len_t len; int foundit = 0; @@ -461,6 +454,8 @@ try_read1msg( assert( lc != NULL ); LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); + LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex ); + LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex ); Debug( LDAP_DEBUG_TRACE, "read1msg: ld %p msgid %d all %d\n", (void *)ld, msgid, all ); @@ -531,7 +526,7 @@ nextresp3: /* if it's been abandoned, toss it */ if ( id > 0 ) { - if ( ldap_abandoned( ld, id, &idx ) ) { + if ( ldap_abandoned( ld, id ) ) { /* the message type */ tag = ber_peek_tag( ber, &len ); switch ( tag ) { @@ -544,7 +539,7 @@ nextresp3: default: /* there's no need to keep the id * in the abandoned list any longer */ - ldap_mark_abandoned( ld, id, idx ); + ldap_mark_abandoned( ld, id ); break; } @@ -1340,35 +1335,37 @@ ldap_msgdelete( LDAP *ld, int msgid ) * * return the location of the message id in the array of abandoned * message ids, or -1 - * - * expects ld_res_mutex to be locked */ static int -ldap_abandoned( LDAP *ld, ber_int_t msgid, int *idxp ) +ldap_abandoned( LDAP *ld, ber_int_t msgid ) { - LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); - - assert( idxp != NULL ); + int ret, idx; assert( msgid >= 0 ); - return ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, idxp ); + LDAP_MUTEX_LOCK( &ld->ld_abandon_mutex ); + ret = ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, &idx ); + LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex ); + return ret; } /* * ldap_mark_abandoned - * - * expects ld_res_mutex to be locked */ static int -ldap_mark_abandoned( LDAP *ld, ber_int_t msgid, int idx ) +ldap_mark_abandoned( LDAP *ld, ber_int_t msgid ) { - LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); + int ret, idx; - /* NOTE: those assertions are repeated in ldap_int_bisect_delete() */ - assert( idx >= 0 ); - assert( (unsigned) idx < ld->ld_nabandoned ); - assert( ld->ld_abandoned[ idx ] == msgid ); - - return ldap_int_bisect_delete( &ld->ld_abandoned, &ld->ld_nabandoned, + assert( msgid >= 0 ); + LDAP_MUTEX_LOCK( &ld->ld_abandon_mutex ); + ret = ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, &idx ); + if (ret <= 0) { /* error or already deleted by another thread */ + LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex ); + return ret; + } + /* still in abandoned array, so delete */ + ret = ldap_int_bisect_delete( &ld->ld_abandoned, &ld->ld_nabandoned, msgid, idx ); + LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex ); + return ret; }