solaar: add locks to prevent multiple persisters for device

This commit is contained in:
Peter F. Patel-Schneider 2024-02-23 08:34:58 -05:00
parent 3954bbd111
commit 8744506259
2 changed files with 29 additions and 22 deletions

View File

@ -74,6 +74,7 @@ class Device:
self._feature_settings_checked = False self._feature_settings_checked = False
self._gestures_lock = _threading.Lock() self._gestures_lock = _threading.Lock()
self._settings_lock = _threading.Lock() self._settings_lock = _threading.Lock()
self._persister_lock = _threading.Lock()
self._notification_handlers = {} # See `add_notification_handler` self._notification_handlers = {} # See `add_notification_handler`
if not self.path: if not self.path:
@ -105,6 +106,7 @@ class Device:
) )
if self.number is None: # for direct-connected devices get 'number' from descriptor protocol else use 0xFF if self.number is None: # for direct-connected devices get 'number' from descriptor protocol else use 0xFF
self.number = 0x00 if self.descriptor and self.descriptor.protocol and self.descriptor.protocol < 2.0 else 0xFF self.number = 0x00 if self.descriptor and self.descriptor.protocol and self.descriptor.protocol < 2.0 else 0xFF
self.ping() # determine whether a direct-connected device is online
if self.descriptor: if self.descriptor:
self._name = self.descriptor.name self._name = self.descriptor.name
@ -306,7 +308,9 @@ class Device:
@property @property
def persister(self): def persister(self):
if not self._persister: if not self._persister:
self._persister = _configuration.persister(self) with self._persister_lock:
if not self._persister:
self._persister = _configuration.persister(self)
return self._persister return self._persister
def battery(self): # None or level, next, status, voltage def battery(self): # None or level, next, status, voltage

View File

@ -122,7 +122,7 @@ def _device_entry_from_config_dict(data, discard_derived_properties):
save_timer = None save_timer = None
save_lock = threading.Lock() configuration_lock = threading.Lock()
defer_saves = False # don't allow configuration saves to be deferred defer_saves = False # don't allow configuration saves to be deferred
@ -140,7 +140,7 @@ def save(defer=False):
if not defer or not defer_saves: if not defer or not defer_saves:
do_save() do_save()
else: else:
with save_lock: with configuration_lock:
if not save_timer: if not save_timer:
save_timer = threading.Timer(5.0, lambda: GLib.idle_add(do_save)) save_timer = threading.Timer(5.0, lambda: GLib.idle_add(do_save))
save_timer.start() save_timer.start()
@ -148,7 +148,7 @@ def save(defer=False):
def do_save(): def do_save():
global save_timer global save_timer
with save_lock: with configuration_lock:
if save_timer: if save_timer:
save_timer.cancel() save_timer.cancel()
save_timer = None save_timer = None
@ -239,25 +239,28 @@ def persister(device):
modelId and modelId == c.get(_KEY_MODEL_ID) and unitId and unitId == c.get(_KEY_UNIT_ID) modelId and modelId == c.get(_KEY_MODEL_ID) and unitId and unitId == c.get(_KEY_UNIT_ID)
) )
if not _config: with configuration_lock:
_load() if not _config:
entry = None _load()
modelId = device.modelId if device.modelId != "000000000000" else device.name if device.modelId else None entry = None
for c in _config: # some devices report modelId and unitId as zero so use name and serial for them
if isinstance(c, _DeviceEntry) and match(device.wpid, device.serial, modelId, device.unitId, c): modelId = device.modelId if device.modelId != "000000000000" else device._name if device.modelId else None
entry = c unitId = device.unitId if device.modelId != "000000000000" else device._serial if device.unitId else None
break for c in _config:
if not entry: if isinstance(c, _DeviceEntry) and match(device.wpid, device._serial, modelId, unitId, c):
if not device.online: # don't create entry for offline devices entry = c
break
if not entry:
if not device.online: # don't create entry for offline devices
if logger.isEnabledFor(logging.INFO):
logger.info("not setting up persister for offline device %s", device._name)
return
if logger.isEnabledFor(logging.INFO): if logger.isEnabledFor(logging.INFO):
logger.info("not setting up persister for offline device %s", device.name) logger.info("setting up persister for device %s", device.name)
return entry = _DeviceEntry()
if logger.isEnabledFor(logging.INFO): _config.append(entry)
logger.info("setting up persister for device %s", device.name) entry.update(device.name, device.wpid, device.serial, modelId, unitId)
entry = _DeviceEntry() return entry
_config.append(entry)
entry.update(device.name, device.wpid, device.serial, modelId, device.unitId)
return entry
def attach_to(device): def attach_to(device):