The LDAPTimer::setTimeout method is called whenever the LDAP connection timeout is updated so that the expiration for the pool's connections can be updated. After scheduling the alarm to expire at the appropriate time, it registers a function that should invoke the callback supplied by the base ConnectionPool class after the background alarm thread resolves the Future that it handed out.
The invoked callback takes a lock on a mutex that is shared by the entire LDAPConnectionPool. This is done because the callback is expected to run on the thread that expired the alarm, which is expected to be different from the one that invoked setTimeout. However, if a sufficiently small timeout is supplied, there is a chance that the alarm may fire immediately, causing the Future to be immediately ready rather than waiting on the background Alarm thread to fulfill the promise. In this case, the callback is run inline, causing it to attempt to take a lock on the mutex that it already holds and thereby deadlock. This could theoretically freeze up the entire LDAPConnectionPool and thereby prevent LDAP-authorized connections from being able to do anything.
To prevent this, LDAPTimer::setTimeout should supply an executor and convert the alarm's future in to an ExecutorFuture. This will guarantee that all callbacks invoked within getAsync() are run out-of-line and should never deadlock.
The fix should end up looking something like how the TLTimer handles this.