buttons: Fix possible ordering issue if a callback blocks

Invoke button callbacks directly from the background thread.  This
ensures that button notifications are delivered and delivered in the
correct order.  Previously, if a callback blocked, it was possible a
new update could start before the previous update was completed, which
could lead to lost events or out of order events.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2023-12-29 14:35:36 -05:00
parent 25bc649cd2
commit 92fe8f15b8
1 changed files with 12 additions and 12 deletions

View File

@ -1,6 +1,6 @@
# Support for button detection and callbacks
#
# Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
# Copyright (C) 2018-2023 Kevin O'Connor <kevin@koconnor.net>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
import logging
@ -69,17 +69,17 @@ class MCU_buttons:
# Send ack to MCU
self.ack_cmd.send([self.oid, new_count])
self.ack_count += new_count
# Call self.handle_button() with this event in main thread
for nb in new_buttons:
self.reactor.register_async_callback(
(lambda e, s=self, b=nb: s.handle_button(e, b)))
def handle_button(self, eventtime, button):
button ^= self.invert
changed = button ^ self.last_button
for mask, shift, callback in self.callbacks:
if changed & mask:
callback(eventtime, (button & mask) >> shift)
self.last_button = button
# Invoke callbacks with this event in main thread
btime = params['#receive_time']
for button in new_buttons:
button ^= self.invert
changed = button ^ self.last_button
self.last_button = button
for mask, shift, callback in self.callbacks:
if changed & mask:
state = (button & mask) >> shift
self.reactor.register_async_callback(
(lambda et, c=callback, bt=btime, s=state: c(bt, s)))
######################################################################