diff options
author | Sven Gothel <[email protected]> | 2020-09-23 06:24:09 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2020-09-23 06:24:09 +0200 |
commit | 26841069fcc95161fdae7b0e4e86bc71f436f088 (patch) | |
tree | 989550b7b9bccb9c94874a14cb870d8d8ed7b882 /api | |
parent | 70dc161e148a11157a22264977b287e707dbdeae (diff) |
DBTAdapter: Split mtx_deviceReferences for each list; Avoid callback-scope locks, leading to deadlocks eventually
Split mtx_deviceReferences into one mtx per list discoveredDevices, connectedDevices and sharedDevices,
allowing us to lock only access to the actual list in a most atomic operation.
+++
Avoid callback-scope locks, leading to deadlocks eventually
A global device-ref mutex (as was mtx_deviceReferences) across the whole callback
method eventually will lead to a deadlock.
This especially as most DBTManager or HCIHandler low-level callbacks
call into all AdapterStatusListener listener.
They would just need to perform one off-thread operation
and access the already locked device-ref mutex to deadlock.
This happened while testing adapter power-off and -on
with running devices.
+++
Reducing the deadlock-surface by using per resource locking
and only at the minimal scope possible avoids this dilemma.
All access method (find, add, remove) already lock their resources with this change.
Since we utilize shared_ptr, after fetching a device it is safe from destruction.
Hence added emphasis on the mtx_sharedDevices,
as the sharedDevices list is the final holder of DBTDevice lifecycle.
In removeDevice(..) and adapter's dtor, we hence lock the mtx_sharedDevice.
Diffstat (limited to 'api')
-rw-r--r-- | api/direct_bt/DBTAdapter.hpp | 6 |
1 files changed, 4 insertions, 2 deletions
diff --git a/api/direct_bt/DBTAdapter.hpp b/api/direct_bt/DBTAdapter.hpp index 894e2b7f..dad7c6bd 100644 --- a/api/direct_bt/DBTAdapter.hpp +++ b/api/direct_bt/DBTAdapter.hpp @@ -177,10 +177,12 @@ namespace direct_bt { std::shared_ptr<HCIHandler> hci; std::vector<std::shared_ptr<DBTDevice>> connectedDevices; std::vector<std::shared_ptr<DBTDevice>> discoveredDevices; // all discovered devices - std::vector<std::shared_ptr<DBTDevice>> sharedDevices; // all active shared devices + std::vector<std::shared_ptr<DBTDevice>> sharedDevices; // All active shared devices. Final holder of DBTDevice lifecycle! std::vector<std::shared_ptr<AdapterStatusListener>> statusListenerList; std::recursive_mutex mtx_hci; - std::recursive_mutex mtx_deviceReferences; // locking: discoveredDevices, connectedDevices and sharedDevices + std::recursive_mutex mtx_discoveredDevices; + std::recursive_mutex mtx_connectedDevices; + std::recursive_mutex mtx_sharedDevices; // Final mutex of all DBTDevice lifecycle! std::recursive_mutex mtx_statusListenerList; std::recursive_mutex mtx_discovery; |