diff --git a/bitbake/lib/bb/event.py b/bitbake/lib/bb/event.py index 952c85c0bd..a12adbc937 100644 --- a/bitbake/lib/bb/event.py +++ b/bitbake/lib/bb/event.py @@ -194,7 +194,12 @@ def fire_ui_handlers(event, d): ui_queue.append(event) return - with bb.utils.lock_timeout(_thread_lock): + with bb.utils.lock_timeout_nocheck(_thread_lock) as lock: + if not lock: + # If we can't get the lock, we may be recursively called, queue and return + ui_queue.append(event) + return + errors = [] for h in _ui_handlers: #print "Sending event %s" % event @@ -213,6 +218,9 @@ def fire_ui_handlers(event, d): for h in errors: del _ui_handlers[h] + while ui_queue: + fire_ui_handlers(ui_queue.pop(), d) + def fire(event, d): """Fire off an Event""" diff --git a/bitbake/lib/bb/utils.py b/bitbake/lib/bb/utils.py index da026fe5bf..67e22f4389 100644 --- a/bitbake/lib/bb/utils.py +++ b/bitbake/lib/bb/utils.py @@ -1857,6 +1857,9 @@ def path_is_descendant(descendant, ancestor): # If we don't have a timeout of some kind and a process/thread exits badly (for example # OOM killed) and held a lock, we'd just hang in the lock futex forever. It is better # we exit at some point than hang. 5 minutes with no progress means we're probably deadlocked. +# This function can still deadlock python since it can't signal the other threads to exit +# (signals are handled in the main thread) and even os._exit() will wait on non-daemon threads +# to exit. @contextmanager def lock_timeout(lock): try: @@ -1869,3 +1872,15 @@ def lock_timeout(lock): finally: lock.release() signal.pthread_sigmask(signal.SIG_SETMASK, s) + +# A version of lock_timeout without the check that the lock was locked and a shorter timeout +@contextmanager +def lock_timeout_nocheck(lock): + try: + s = signal.pthread_sigmask(signal.SIG_BLOCK, signal.valid_signals()) + l = lock.acquire(timeout=10) + yield l + finally: + if l: + lock.release() + signal.pthread_sigmask(signal.SIG_SETMASK, s)