From 84c51a14111528a8220111dbffb7a423345a23f6 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Wed, 2 Mar 2022 21:19:12 +0100 Subject: [PATCH] Fix BaseUI x-thread signal vs thread-start race Control surfaces c'tor usually subscribe to signals e.g. PortConnectedOrDisconnected. This happens after the parent BaseUI is created, but before set_active() -> BaseUI::run() is called. At this point in time there is no run_loop thread. There are two options to handle AbstractUI::call_slot(): A. Queue the event in the event-loop, using the thread-local request buffer of the caller. Then hope the BaseUI thread is started, and calls ::handle_ui_requests() before the memory pool runs out of space. B. Handle the event in the calling thread. -- This may not be rt-safe and may call functions with locks held by the caller. It will however not accumulate events. This takes approach (B). If _run_loop_thread is NULL, directly handle the signal. In the past, prior to 50abcc74b5dab573f, approach (A) was taken. NULL never matched Glib::Threads::Thread::self(). This also reverts a prior attempt (e417495505) to address this issue. --- libs/pbd/base_ui.cc | 3 +-- libs/pbd/pbd/base_ui.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libs/pbd/base_ui.cc b/libs/pbd/base_ui.cc index 6c9a095d6d..83df2b76b5 100644 --- a/libs/pbd/base_ui.cc +++ b/libs/pbd/base_ui.cc @@ -119,12 +119,11 @@ BaseUI::run () m_context = MainContext::create(); _main_loop = MainLoop::create (m_context); + attach_request_source (); Glib::Threads::Mutex::Lock lm (_run_lock); _run_loop_thread = PBD::Thread::create (boost::bind (&BaseUI::main_thread, this)); _running.wait (_run_lock); - - attach_request_source (); } void diff --git a/libs/pbd/pbd/base_ui.h b/libs/pbd/pbd/base_ui.h index 27bdb71644..fff6f5da84 100644 --- a/libs/pbd/pbd/base_ui.h +++ b/libs/pbd/pbd/base_ui.h @@ -53,7 +53,7 @@ class LIBPBD_API BaseUI : public sigc::trackable, public PBD::EventLoop BaseUI* base_instance() { return base_ui_instance; } Glib::RefPtr main_loop() const { return _main_loop; } - bool caller_is_self () const { assert (_run_loop_thread); return _run_loop_thread->caller_is_self (); } + bool caller_is_self () const { return _run_loop_thread ? _run_loop_thread->caller_is_self () : true; } bool ok() const { return _ok; }