From 14c0e36a0083e138729aab57f85e23a5bbc54a75 Mon Sep 17 00:00:00 2001 From: Joseph Nobes Date: Thu, 15 Aug 2024 14:35:21 +0100 Subject: [PATCH] Register Controller released on exception in context Previously, when used with 'with', if an exception was encountered while inside the managed context, the yield would return and raise it without ever releasing the mutex. This meant that any error while reading the ASIC fields / registers resulted in the whole system locking up. For example, this was seen in the babyd-embedded implementation both when disabling the ASIC interface during reset, and additionally when attempting to write to any field that did not exist. The errors are still raised, but the mutex is also handled properly with a 'finally' block such that the system can continue running. The user should still handle whatever exception has been raised. --- control/loki/register_controller.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/control/loki/register_controller.py b/control/loki/register_controller.py index ec0a2bc..c2efa4f 100644 --- a/control/loki/register_controller.py +++ b/control/loki/register_controller.py @@ -277,13 +277,22 @@ def acquire(self, blocking=True, timeout=-1): # Grab the lock with the supplied settings result = self._register_mutex.acquire(blocking=blocking, timeout=timeout) - # Allow the caller to execute their 'with'. 'result' is needed so that - # if the lock cannot be grabbed the user can handle it. - yield result - - # Release the lock, if it was actually acquired - if result: - self._register_mutex.release() + try: + # Allow the caller to execute their 'with'. 'result' is needed so that + # if the lock cannot be grabbed the user can handle it. + yield result + + except: + # Pass through any exception + raise + + finally: + # Even if there is an exception, release the lock so that it doesn't lock up the ASIC + # access. This will only release the lock if it was actually gained in the first place. + + # Release the lock, if it was actually acquired + if result: + self._register_mutex.release() def get_word_width(self): return self._word_width_bits