Skip to content

Fix DeviceManagerStorage to be thread-safe

Dāvis Mosāns requested to merge davism/solid:master into master

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);
}

Merge request reports