From 6465921a5adb3a3335494598463066a6c3540cb5 Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Sat, 18 Oct 2025 13:05:54 -0400 Subject: [PATCH] gcode_macro: Verify nothing attempts to pause in a get_status() callback Signed-off-by: Kevin O'Connor --- klippy/extras/gcode_macro.py | 7 ++-- klippy/webhooks.py | 67 ++++++++++++++++++------------------ 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/klippy/extras/gcode_macro.py b/klippy/extras/gcode_macro.py index 3aa5087b1..58861fd89 100644 --- a/klippy/extras/gcode_macro.py +++ b/klippy/extras/gcode_macro.py @@ -24,9 +24,12 @@ class GetStatusWrapper: po = self.printer.lookup_object(sval, None) if po is None or not hasattr(po, 'get_status'): raise KeyError(val) + reactor = self.printer.get_reactor() if self.eventtime is None: - self.eventtime = self.printer.get_reactor().monotonic() - self.cache[sval] = res = copy.deepcopy(po.get_status(self.eventtime)) + self.eventtime = reactor.monotonic() + with reactor.assert_no_pause(): + sts = po.get_status(self.eventtime) + self.cache[sval] = res = copy.deepcopy(sts) return res def __contains__(self, val): try: diff --git a/klippy/webhooks.py b/klippy/webhooks.py index 78edc6e5b..da18bff5e 100644 --- a/klippy/webhooks.py +++ b/klippy/webhooks.py @@ -491,41 +491,42 @@ class QueryStatusHelper: self.pending_queries = [] msglist.extend(self.clients.values()) # Generate get_status() info for each client - for cconn, subscription, send_func, template in msglist: - is_query = cconn is None - if not is_query and cconn.is_closed(): - del self.clients[cconn] - continue - # Query each requested printer object - cquery = {} - for obj_name, req_items in subscription.items(): - res = query.get(obj_name, None) - if res is None: - po = self.printer.lookup_object(obj_name, None) - if po is None or not hasattr(po, 'get_status'): - res = query[obj_name] = {} - else: - res = query[obj_name] = po.get_status(eventtime) - if req_items is None: - req_items = list(res.keys()) - if req_items: - subscription[obj_name] = req_items - lres = last_query.get(obj_name, {}) - cres = {} - for ri in req_items: - rd = res.get(ri, None) - if is_query or rd != lres.get(ri): - cres[ri] = rd - if cres or is_query: - cquery[obj_name] = cres - # Send data - if cquery or is_query: - tmp = dict(template) - tmp['params'] = {'eventtime': eventtime, 'status': cquery} - send_func(tmp) + reactor = self.printer.get_reactor() + with reactor.assert_no_pause(): + for cconn, subscription, send_func, template in msglist: + is_query = cconn is None + if not is_query and cconn.is_closed(): + del self.clients[cconn] + continue + # Query each requested printer object + cquery = {} + for obj_name, req_items in subscription.items(): + res = query.get(obj_name, None) + if res is None: + po = self.printer.lookup_object(obj_name, None) + if po is None or not hasattr(po, 'get_status'): + res = query[obj_name] = {} + else: + res = query[obj_name] = po.get_status(eventtime) + if req_items is None: + req_items = list(res.keys()) + if req_items: + subscription[obj_name] = req_items + lres = last_query.get(obj_name, {}) + cres = {} + for ri in req_items: + rd = res.get(ri, None) + if is_query or rd != lres.get(ri): + cres[ri] = rd + if cres or is_query: + cquery[obj_name] = cres + # Send data + if cquery or is_query: + tmp = dict(template) + tmp['params'] = {'eventtime': eventtime, 'status': cquery} + send_func(tmp) if not query: # Unregister timer if there are no longer any subscriptions - reactor = self.printer.get_reactor() reactor.unregister_timer(self.query_timer) self.query_timer = None return reactor.NEVER