Fix DeviceManagerStorage to be thread-safe
DeviceManagerPrivate
is expected to be reentrant - DeviceManagerStorage::ensureManagerCreated
creates
new instance for every thread.
But without this change it wasn't because in ManagerBasePrivate::loadBackends
some backends use global shared state.
For example IMobile::Manager
uses libimobiledevice
library where in destructor it calls idevice_event_unsubscribe()
(without any arguments) which is not safe to be invoked from multiple threads.
So make ManagerBasePrivate
(also renamed to BackendManagerPrivate
) to be global shared singleton that is used by all DeviceManagerPrivate
instances.
I noticed this crash when Solid::Device::Device(udi)
is used from multiple threads
Stack trace of thread 13186:
#0 0x00007f29256b12b3 n/a (libc.so.6 + 0x8e2b3)
#1 0x00007f2922da42ec n/a (libusbmuxd-2.0.so.6 + 0x72ec)
#2 0x00007f2922da12b0 usbmuxd_events_unsubscribe (libusbmuxd-2.0.so.6 + 0x42b0)
#3 0x00007f2922da1354 usbmuxd_subscribe (libusbmuxd-2.0.so.6 + 0x4354)
#4 0x00007f2924696488 idevice_event_subscribe (libimobiledevice-1.0.so.6 + 0x9488)
#5 0x00007f2927610dbe n/a (libKF5Solid.so.5 + 0xaadbe)
#6 0x00007f29275a3152 n/a (libKF5Solid.so.5 + 0x3d152)
#7 0x00007f29275a6b0a n/a (libKF5Solid.so.5 + 0x40b0a)
#8 0x00007f29275a6d16 _ZN5Solid14DeviceNotifier8instanceEv (libKF5Solid.so.5 + 0x40d16)
#9 0x00007f29275a5399 _ZN5Solid6DeviceC1ERK7QString (libKF5Solid.so.5 + 0x3f399)
#10 0x00007f29275a550c _ZNK5Solid6Device6parentEv (libKF5Solid.so.5 + 0x3f50c)
...
Stack trace of thread 13184:
#0 0x00007f29256ac119 n/a (libc.so.6 + 0x89119)
#1 0x00007f29256b1113 n/a (libc.so.6 + 0x8e113)
#2 0x00007f2922da12dc usbmuxd_events_unsubscribe (libusbmuxd-2.0.so.6 + 0x42dc)
#3 0x00007f2922da1354 usbmuxd_subscribe (libusbmuxd-2.0.so.6 + 0x4354)
#4 0x00007f2924696488 idevice_event_subscribe (libimobiledevice-1.0.so.6 + 0x9488)
#5 0x00007f2927610dbe n/a (libKF5Solid.so.5 + 0xaadbe)
#6 0x00007f29275a3152 n/a (libKF5Solid.so.5 + 0x3d152)
#7 0x00007f29275a6b0a n/a (libKF5Solid.so.5 + 0x40b0a)
#8 0x00007f29275a6d16 _ZN5Solid14DeviceNotifier8instanceEv (libKF5Solid.so.5 + 0x40d16)
#9 0x00007f29275a5399 _ZN5Solid6DeviceC1ERK7QString (libKF5Solid.so.5 + 0x3f399)
#10 0x00007f29275a550c _ZNK5Solid6Device6parentEv (libKF5Solid.so.5 + 0x3f50c)
...
Stack trace of thread 13156:
#0 0x00007f29256ac119 n/a (libc.so.6 + 0x89119)
#1 0x00007f29256b1113 n/a (libc.so.6 + 0x8e113)
#2 0x00007f2922da12dc usbmuxd_events_unsubscribe (libusbmuxd-2.0.so.6 + 0x42dc)
#3 0x00007f2922da1354 usbmuxd_subscribe (libusbmuxd-2.0.so.6 + 0x4354)
#4 0x00007f2924696488 idevice_event_subscribe (libimobiledevice-1.0.so.6 + 0x9488)
#5 0x00007f2927610dbe n/a (libKF5Solid.so.5 + 0xaadbe)
#6 0x00007f29275a3152 n/a (libKF5Solid.so.5 + 0x3d152)
#7 0x00007f29275a6b0a n/a (libKF5Solid.so.5 + 0x40b0a)
#8 0x00007f29275a6d16 _ZN5Solid14DeviceNotifier8instanceEv (libKF5Solid.so.5 + 0x40d16)
#9 0x00007f29275a5399 _ZN5Solid6DeviceC1ERK7QString (libKF5Solid.so.5 + 0x3f399)
#10 0x00007f29275a550c _ZNK5Solid6Device6parentEv (libKF5Solid.so.5 + 0x3f50c)
...
Solid::Device::Device(const QString &udi)
{
// crashes inside Solid::DeviceNotifier::instance()
// because `ManagerBasePrivate` loads and unloads backends in every thread
DeviceManagerPrivate *manager = static_cast<DeviceManagerPrivate *>(Solid::DeviceNotifier::instance());
d = manager->findRegisteredDevice(udi);
}