From ce3da71d81bed91003c8215992fb3786cad9888c Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Wed, 22 Nov 2023 18:22:47 +0100 Subject: [PATCH] ui/vnc: wait for server setup before rendering ui::vnc::setup() creates the vnc server screen at m_screen which is used by ui::vnc::render() to mark the screen rectangle as modified. However, m_screen is created in a separate thread and there is no protection to ensure m_screen has been initialized before using it. Protect rendering by using the currently unused m_mutex and a condition_variable to wait for the vnc server to be properly set up. Signed-off-by: Sebastian Hesselbarth --- include/vcml/core/types.h | 1 + src/vcml/ui/vnc.cpp | 18 ++++++++++++++++++ src/vcml/ui/vnc.h | 4 ++++ 3 files changed, 23 insertions(+) diff --git a/include/vcml/core/types.h b/include/vcml/core/types.h index 7351ae43..9c4e3cf6 100644 --- a/include/vcml/core/types.h +++ b/include/vcml/core/types.h @@ -151,6 +151,7 @@ using std::atomic; using std::mutex; using std::lock_guard; +using std::unique_lock; using std::condition_variable; using std::condition_variable_any; using std::thread; diff --git a/src/vcml/ui/vnc.cpp b/src/vcml/ui/vnc.cpp index 2c36ea5c..2372d001 100644 --- a/src/vcml/ui/vnc.cpp +++ b/src/vcml/ui/vnc.cpp @@ -266,6 +266,7 @@ void vnc::run() { log_debug("starting vnc server on port %d", m_screen->port); + set_ready(); while (m_running && rfbIsActive(m_screen) && sim_running()) rfbProcessEvents(m_screen, 1000); @@ -283,6 +284,8 @@ vnc::vnc(u32 no): m_ptr_y(), m_running(false), m_mutex(), + m_cond_ready(), + m_ready(false), m_screen(), m_thread() { VCML_ERROR_ON(no != (u32)m_port, "invalid port specified: %u", no); @@ -295,9 +298,22 @@ vnc::~vnc() { // nothing to do } +void vnc::wait_ready() { + unique_lock lock(m_mutex); + while (!m_ready) + m_cond_ready.wait(lock); +} + +void vnc::set_ready() { + unique_lock lock(m_mutex); + m_ready = true; + m_cond_ready.notify_one(); +} + void vnc::init(const videomode& mode, u8* fb) { display::init(mode, fb); + m_ready = false; m_running = true; m_thread = thread(&vnc::run, this); mwr::set_thread_name(m_thread, name()); @@ -309,6 +325,8 @@ void vnc::render(u32 x, u32 y, u32 w, u32 h) { if (y + h > yres()) h = yres() - y; + if (!m_ready) + wait_ready(); rfbMarkRectAsModified(m_screen, x, y, x + w, y + h); } diff --git a/src/vcml/ui/vnc.h b/src/vcml/ui/vnc.h index c25580eb..0b2165ab 100644 --- a/src/vcml/ui/vnc.h +++ b/src/vcml/ui/vnc.h @@ -35,10 +35,14 @@ private: u32 m_ptr_y; atomic m_running; mutex m_mutex; + condition_variable m_cond_ready; + atomic m_ready; rfbScreenInfo* m_screen; thread m_thread; void run(); + void wait_ready(); + void set_ready(); public: u16 port() const { return m_port; } -- 2.34.1