Skip to content

Commit f8fbc03

Browse files
authored
core: prevent lockup on connection destruction (#2412)
When we destroy Mavsdk and clear the list of connections, we likely end up in a deadlock. What happens is that: 1. A connection wants to forward a message and is trying to acquire the connection mutex. 2. At the same time, the connection is being destroyed, so we are waiting for the connection receive thread to be joinable. While the connections are being destroyed, we have the connection mutex which is blocking 1. The proposed solution is to: 1. Make it less likely by acquiring the connection mutex properly before checking _connections.size() and not for the individual connections. 2. Check the _should_exit flag before trying to acquire the mutex. I believe by the time the connections are being cleared, this flag is set, and hence the deadlock should not happen, fingers crossed.
1 parent 0a825ac commit f8fbc03

File tree

1 file changed

+23
-10
lines changed

1 file changed

+23
-10
lines changed

src/mavsdk/core/mavsdk_impl.cpp

+23-10
Original file line numberDiff line numberDiff line change
@@ -292,8 +292,6 @@ void MavsdkImpl::forward_message(mavlink_message_t& message, Connection* connect
292292
(message.msgid != MAVLINK_MSG_ID_HEARTBEAT || forward_heartbeats_enabled);
293293

294294
if (!targeted_only_at_us && heartbeat_check_ok) {
295-
std::lock_guard<std::mutex> lock(_connections_mutex);
296-
297295
unsigned successful_emissions = 0;
298296
for (auto& entry : _connections) {
299297
// Check whether the connection is not the one from which we received the message.
@@ -319,6 +317,11 @@ void MavsdkImpl::receive_message(mavlink_message_t& message, Connection* connect
319317
<< static_cast<int>(message.sysid) << "/" << static_cast<int>(message.compid);
320318
}
321319

320+
if (_should_exit) {
321+
// If we're meant to clean up, let's not try to acquire any more locks but bail.
322+
return;
323+
}
324+
322325
// This is a low level interface where incoming messages can be tampered
323326
// with or even dropped.
324327
{
@@ -332,6 +335,11 @@ void MavsdkImpl::receive_message(mavlink_message_t& message, Connection* connect
332335
}
333336
}
334337

338+
if (_should_exit) {
339+
// If we're meant to clean up, let's not try to acquire any more locks but bail.
340+
return;
341+
}
342+
335343
/** @note: Forward message if option is enabled and multiple interfaces are connected.
336344
* Performs message forwarding checks for every messages if message forwarding
337345
* is enabled on at least one connection, and in case of a single forwarding connection,
@@ -342,15 +350,20 @@ void MavsdkImpl::receive_message(mavlink_message_t& message, Connection* connect
342350
* 2. At least 1 forwarding connection.
343351
* 3. At least 2 forwarding connections or current connection is not forwarding.
344352
*/
345-
if (_connections.size() > 1 && mavsdk::Connection::forwarding_connections_count() > 0 &&
346-
(mavsdk::Connection::forwarding_connections_count() > 1 ||
347-
!connection->should_forward_messages())) {
348-
if (_message_logging_on) {
349-
LogDebug() << "Forwarding message " << message.msgid << " from "
350-
<< static_cast<int>(message.sysid) << "/"
351-
<< static_cast<int>(message.compid);
353+
354+
{
355+
std::lock_guard<std::mutex> lock(_connections_mutex);
356+
357+
if (_connections.size() > 1 && mavsdk::Connection::forwarding_connections_count() > 0 &&
358+
(mavsdk::Connection::forwarding_connections_count() > 1 ||
359+
!connection->should_forward_messages())) {
360+
if (_message_logging_on) {
361+
LogDebug() << "Forwarding message " << message.msgid << " from "
362+
<< static_cast<int>(message.sysid) << "/"
363+
<< static_cast<int>(message.compid);
364+
}
365+
forward_message(message, connection);
352366
}
353-
forward_message(message, connection);
354367
}
355368

356369
// Don't ever create a system with sysid 0.

0 commit comments

Comments
 (0)