Details
-
Bug
-
Status: Resolved
-
Major
-
Resolution: Fixed
-
None
Description
The Connection abstraction is prone to deadlocks arising from last reference of Connection getting destructed by the ConnectionProcess execution context, at which point ConnectionProcess waits on itself (deadlock).
Consider this example:
Option<Connection> connection = process::http::connect(...).get(); // When the ConnectionProcess completes the Future, if 'connection' // is the last copy of the Connection it will wait on itself! connection.disconnected() .onAny(defer(self(), &SomeFunc, connection)); connection.disconnect(); connection = None();
In the above snippet, deadlock can occur as follows:
1. Connection = None() executes, the last copy of the Connection remains within the disconnected Future.
2. ConnectionProcess::disconnect completes the disconnection Future and executes SomeFunc. The Future then clears the callbacks which destructs the last copy of the Connection.
3. Connection::~Data waits on the ConnectionProcess from within the ConnectionProcess execution context. Deadlock.
We do have a snippet in our existing code that alludes to such occurrences happening:
https://github.com/apache/mesos/blob/master/3rdparty/libprocess/src/http.cpp#L1325
// This is a one time request which will close the connection when // the response is received. Since 'Connection' is reference-counted, // we must keep a copy around until the disconnection occurs. Note // that in order to avoid a deadlock (Connection destruction occurring // from the ConnectionProcess execution context), we use 'async'.