mirror of
https://git.openldap.org/openldap/openldap.git
synced 2026-02-03 20:40:05 -05:00
Fix races with backend_retry
This commit is contained in:
parent
c087244265
commit
81ead4a5f4
1 changed files with 41 additions and 11 deletions
|
|
@ -38,6 +38,12 @@ upstream_connect_cb( evutil_socket_t s, short what, void *arg )
|
|||
Debug( LDAP_DEBUG_CONNS, "upstream_connect_cb: "
|
||||
"fd=%d connection callback for backend uri='%s'\n",
|
||||
s, b->b_uri.bv_val );
|
||||
|
||||
if ( s != conn->fd ) {
|
||||
/* backend_reset has been here first */
|
||||
goto preempted;
|
||||
}
|
||||
|
||||
if ( what == EV_WRITE ) {
|
||||
socklen_t optlen = sizeof(error);
|
||||
|
||||
|
|
@ -74,9 +80,8 @@ done:
|
|||
error ? sock_errstr( error, ebuf, sizeof(ebuf) ) : "" );
|
||||
}
|
||||
backend_retry( b );
|
||||
} else {
|
||||
b->b_failed = 0;
|
||||
}
|
||||
preempted:
|
||||
ldap_pvt_thread_mutex_unlock( &b->b_mutex );
|
||||
|
||||
event_free( conn->event );
|
||||
|
|
@ -485,22 +490,39 @@ backend_connect_task( void *ctx, void *arg )
|
|||
}
|
||||
|
||||
/*
|
||||
* Needs exclusive access to the backend.
|
||||
* Needs exclusive access to the backend and no other thread is allowed to call
|
||||
* backend_retry while we're handling this.
|
||||
*
|
||||
* If gentle == 0, a full pause must be in effect, else we risk deadlocking on
|
||||
* event_free().
|
||||
*/
|
||||
void
|
||||
backend_reset( LloadBackend *b, int gentle )
|
||||
{
|
||||
if ( b->b_cookie ) {
|
||||
int rc;
|
||||
rc = ldap_pvt_thread_pool_retract( b->b_cookie );
|
||||
assert( rc == 1 );
|
||||
b->b_cookie = NULL;
|
||||
b->b_opening--;
|
||||
if ( ldap_pvt_thread_pool_retract( b->b_cookie ) ) {
|
||||
b->b_cookie = NULL;
|
||||
b->b_opening--;
|
||||
} else {
|
||||
/*
|
||||
* The task might not be cancelable because it just started
|
||||
* executing.
|
||||
*
|
||||
* Shutdown should be the only time when the thread pool is
|
||||
* in that state. Keep the cookie in to keep an eye on whether
|
||||
* it's finished yet.
|
||||
*/
|
||||
assert( slapd_shutdown );
|
||||
}
|
||||
}
|
||||
/* Not safe to hold our mutex and call event_del/free if the event's
|
||||
* callback is running, relinquish the mutex while we do so. */
|
||||
if ( b->b_retry_event &&
|
||||
event_pending( b->b_retry_event, EV_TIMEOUT, NULL ) ) {
|
||||
assert( b->b_failed );
|
||||
ldap_pvt_thread_mutex_unlock( &b->b_mutex );
|
||||
event_del( b->b_retry_event );
|
||||
ldap_pvt_thread_mutex_lock( &b->b_mutex );
|
||||
b->b_opening--;
|
||||
}
|
||||
if ( b->b_dns_req ) {
|
||||
|
|
@ -515,16 +537,24 @@ backend_reset( LloadBackend *b, int gentle )
|
|||
"destroying socket pending connect() fd=%d\n",
|
||||
pending->fd );
|
||||
|
||||
event_free( pending->event );
|
||||
event_active( pending->event, EV_WRITE, 0 );
|
||||
evutil_closesocket( pending->fd );
|
||||
pending->fd = -1;
|
||||
LDAP_LIST_REMOVE( pending, next );
|
||||
ch_free( pending );
|
||||
|
||||
if ( !gentle ) {
|
||||
/* None of the event bases are running, we're safe to free the
|
||||
* event right now and potentially free the backend itself */
|
||||
event_free( pending->event );
|
||||
ch_free( pending );
|
||||
}
|
||||
/* else, just let the event dispose of the resources on its own later */
|
||||
b->b_opening--;
|
||||
}
|
||||
connections_walk(
|
||||
&b->b_mutex, &b->b_preparing, lload_connection_close, &gentle );
|
||||
assert( LDAP_CIRCLEQ_EMPTY( &b->b_preparing ) );
|
||||
assert( b->b_opening == 0 );
|
||||
assert( b->b_opening == ( b->b_cookie ? 1 : 0 ) );
|
||||
b->b_failed = 0;
|
||||
|
||||
connections_walk_last( &b->b_mutex, &b->b_bindconns, b->b_last_bindconn,
|
||||
|
|
|
|||
Loading…
Reference in a new issue