[client] app: make shared application state access thread-safe

This commit is contained in:
Geoffrey McRae
2026-07-28 12:41:35 +10:00
parent f980248221
commit f4ee349880
4 changed files with 85 additions and 67 deletions

View File

@@ -45,9 +45,10 @@
bool app_isRunning(void) bool app_isRunning(void)
{ {
const enum RunState state = app_getState();
return return
g_state.state == APP_STATE_RUNNING || state == APP_STATE_RUNNING ||
g_state.state == APP_STATE_RESTART; state == APP_STATE_RESTART;
} }
bool app_isCaptureMode(void) bool app_isCaptureMode(void)
@@ -189,7 +190,7 @@ void app_handleFocusEvent(bool focused)
if (g_params.releaseKeysOnFocusLoss) if (g_params.releaseKeysOnFocusLoss)
for (int key = 0; key < KEY_MAX; key++) for (int key = 0; key < KEY_MAX; key++)
if (g_state.keyDown[key]) if (atomic_load_explicit(&g_state.keyDown[key], memory_order_relaxed))
app_handleKeyReleaseInternal(key); app_handleKeyReleaseInternal(key);
g_state.escapeActive = false; g_state.escapeActive = false;
@@ -432,14 +433,14 @@ void app_handleKeyPressInternal(int sc)
if (g_params.ignoreWindowsKeys && (sc == KEY_LEFTMETA || sc == KEY_RIGHTMETA)) if (g_params.ignoreWindowsKeys && (sc == KEY_LEFTMETA || sc == KEY_RIGHTMETA))
return; return;
if (!g_state.keyDown[sc]) if (!atomic_load_explicit(&g_state.keyDown[sc], memory_order_relaxed))
{ {
uint32_t ps2 = linux_to_ps2[sc]; uint32_t ps2 = linux_to_ps2[sc];
if (!ps2) if (!ps2)
return; return;
if (purespice_keyDown(ps2)) if (purespice_keyDown(ps2))
g_state.keyDown[sc] = true; atomic_store_explicit(&g_state.keyDown[sc], true, memory_order_relaxed);
else else
{ {
DEBUG_ERROR("app_handleKeyPress: failed to send message"); DEBUG_ERROR("app_handleKeyPress: failed to send message");
@@ -474,7 +475,7 @@ void app_handleKeyReleaseInternal(int sc)
return; return;
// avoid sending key up events when we didn't send a down // avoid sending key up events when we didn't send a down
if (!g_state.keyDown[sc]) if (!atomic_load_explicit(&g_state.keyDown[sc], memory_order_relaxed))
return; return;
if (g_params.ignoreWindowsKeys && (sc == KEY_LEFTMETA || sc == KEY_RIGHTMETA)) if (g_params.ignoreWindowsKeys && (sc == KEY_LEFTMETA || sc == KEY_RIGHTMETA))
@@ -485,7 +486,7 @@ void app_handleKeyReleaseInternal(int sc)
return; return;
if (purespice_keyUp(ps2)) if (purespice_keyUp(ps2))
g_state.keyDown[sc] = false; atomic_store_explicit(&g_state.keyDown[sc], false, memory_order_relaxed);
else else
{ {
DEBUG_ERROR("app_handleKeyRelease: failed to send message"); DEBUG_ERROR("app_handleKeyRelease: failed to send message");
@@ -648,7 +649,7 @@ void app_invalidateWindow(bool full)
void app_handleCloseEvent(void) void app_handleCloseEvent(void)
{ {
if (!g_params.ignoreQuit || !g_cursor.inView) if (!g_params.ignoreQuit || !g_cursor.inView)
g_state.state = APP_STATE_SHUTDOWN; app_setState(APP_STATE_SHUTDOWN);
} }
void app_handleRenderEvent(const uint64_t timeUs) void app_handleRenderEvent(const uint64_t timeUs)
@@ -1099,7 +1100,7 @@ void app_overlayConfigRegisterTab(const char * title,
void app_invalidateOverlay(bool renderTwice) void app_invalidateOverlay(bool renderTwice)
{ {
if (g_state.state == APP_STATE_SHUTDOWN) if (app_getState() == APP_STATE_SHUTDOWN)
return; return;
if (renderTwice) if (renderTwice)
@@ -1138,7 +1139,7 @@ void app_stopVideo(bool stop)
return; return;
// do not change the state if the host app is not connected // do not change the state if the host app is not connected
if (!g_state.lgHostConnected) if (!atomic_load_explicit(&g_state.lgHostConnected, memory_order_acquire))
return; return;
g_state.stopVideo = stop; g_state.stopVideo = stop;
@@ -1169,7 +1170,7 @@ bool app_useSpiceDisplay(bool enable)
memory_order_release); memory_order_release);
// if spice is not yet ready, flag the state we want for when it is // if spice is not yet ready, flag the state we want for when it is
if (!g_state.spiceReady) if (!atomic_load_explicit(&g_state.spiceReady, memory_order_acquire))
return false; return false;
bool active = atomic_load_explicit(&g_state.spiceDisplayActive, bool active = atomic_load_explicit(&g_state.spiceDisplayActive,
@@ -1178,7 +1179,8 @@ bool app_useSpiceDisplay(bool enable)
return active; return active;
// do not allow stopping of the host app if not connected // do not allow stopping of the host app if not connected
if (!enable && !g_state.lgHostConnected) if (!enable && !atomic_load_explicit(
&g_state.lgHostConnected, memory_order_acquire))
{ {
atomic_store_explicit(&g_state.spiceDisplayRequested, active, atomic_store_explicit(&g_state.spiceDisplayRequested, active,
memory_order_release); memory_order_release);

View File

@@ -66,7 +66,7 @@ static void bind_input(int sc, void * opaque)
static void bind_quit(int sc, void * opaque) static void bind_quit(int sc, void * opaque)
{ {
g_state.state = APP_STATE_SHUTDOWN; app_setState(APP_STATE_SHUTDOWN);
} }
static void bind_mouseSens(int sc, void * opaque) static void bind_mouseSens(int sc, void * opaque)

View File

@@ -176,7 +176,7 @@ static int renderThread(void * unused)
if (!RENDERER(renderStartup, g_state.useDMA)) if (!RENDERER(renderStartup, g_state.useDMA))
{ {
DEBUG_ERROR("EGL render failed to start"); DEBUG_ERROR("EGL render failed to start");
g_state.state = APP_STATE_SHUTDOWN; app_setState(APP_STATE_SHUTDOWN);
/* unblock threads waiting on the condition */ /* unblock threads waiting on the condition */
lgSignalEvent(e_startup); lgSignalEvent(e_startup);
@@ -211,7 +211,7 @@ static int renderThread(void * unused)
struct timespec time; struct timespec time;
clock_gettime(CLOCK_MONOTONIC, &time); clock_gettime(CLOCK_MONOTONIC, &time);
while(likely(g_state.state != APP_STATE_SHUTDOWN)) while(likely(app_getState() != APP_STATE_SHUTDOWN))
{ {
if (g_state.jitRender) if (g_state.jitRender)
{ {
@@ -328,7 +328,7 @@ static int renderThread(void * unused)
} }
} }
g_state.state = APP_STATE_SHUTDOWN; app_setState(APP_STATE_SHUTDOWN);
if (g_state.overlays) if (g_state.overlays)
{ {
@@ -360,7 +360,7 @@ int main_cursorThread(void * unused)
lgWaitEvent(e_startup, TIMEOUT_INFINITE); lgWaitEvent(e_startup, TIMEOUT_INFINITE);
// subscribe to the pointer queue // subscribe to the pointer queue
while(g_state.state == APP_STATE_RUNNING) while(app_getState() == APP_STATE_RUNNING)
{ {
status = lgmpClientSubscribe(g_state.lgmp, LGMP_Q_POINTER, status = lgmpClientSubscribe(g_state.lgmp, LGMP_Q_POINTER,
&g_state.pointerQueue); &g_state.pointerQueue);
@@ -374,11 +374,11 @@ int main_cursorThread(void * unused)
} }
DEBUG_ERROR("lgmpClientSubscribe Failed: %s", lgmpStatusString(status)); DEBUG_ERROR("lgmpClientSubscribe Failed: %s", lgmpStatusString(status));
g_state.state = APP_STATE_SHUTDOWN; app_setState(APP_STATE_SHUTDOWN);
break; break;
} }
while(g_state.state == APP_STATE_RUNNING && !g_state.stopVideo) while(app_getState() == APP_STATE_RUNNING && !g_state.stopVideo)
{ {
LGMPMessage msg; LGMPMessage msg;
if ((status = lgmpClientProcess(g_state.pointerQueue, &msg)) != LGMP_OK) if ((status = lgmpClientProcess(g_state.pointerQueue, &msg)) != LGMP_OK)
@@ -421,11 +421,11 @@ int main_cursorThread(void * unused)
} }
if (status == LGMP_ERR_INVALID_SESSION) if (status == LGMP_ERR_INVALID_SESSION)
g_state.state = APP_STATE_RESTART; app_setState(APP_STATE_RESTART);
else else
{ {
DEBUG_ERROR("lgmpClientProcess Failed: %s", lgmpStatusString(status)); DEBUG_ERROR("lgmpClientProcess Failed: %s", lgmpStatusString(status));
g_state.state = APP_STATE_SHUTDOWN; app_setState(APP_STATE_SHUTDOWN);
} }
break; break;
} }
@@ -450,7 +450,7 @@ int main_cursorThread(void * unused)
if (!cursor) if (!cursor)
{ {
DEBUG_ERROR("failed to allocate %d bytes for cursor", neededSize); DEBUG_ERROR("failed to allocate %d bytes for cursor", neededSize);
g_state.state = APP_STATE_SHUTDOWN; app_setState(APP_STATE_SHUTDOWN);
break; break;
} }
cursorSize = neededSize; cursorSize = neededSize;
@@ -575,11 +575,11 @@ int main_frameThread(void * unused)
DEBUG_INFO("Using DMA buffer support"); DEBUG_INFO("Using DMA buffer support");
lgWaitEvent(e_startup, TIMEOUT_INFINITE); lgWaitEvent(e_startup, TIMEOUT_INFINITE);
if (g_state.state != APP_STATE_RUNNING) if (app_getState() != APP_STATE_RUNNING)
return 0; return 0;
// subscribe to the frame queue // subscribe to the frame queue
while(g_state.state == APP_STATE_RUNNING) while(app_getState() == APP_STATE_RUNNING)
{ {
status = lgmpClientSubscribe(g_state.lgmp, LGMP_Q_FRAME, &queue); status = lgmpClientSubscribe(g_state.lgmp, LGMP_Q_FRAME, &queue);
if (status == LGMP_OK) if (status == LGMP_OK)
@@ -592,11 +592,11 @@ int main_frameThread(void * unused)
} }
DEBUG_ERROR("lgmpClientSubscribe Failed: %s", lgmpStatusString(status)); DEBUG_ERROR("lgmpClientSubscribe Failed: %s", lgmpStatusString(status));
g_state.state = APP_STATE_SHUTDOWN; app_setState(APP_STATE_SHUTDOWN);
break; break;
} }
while(g_state.state == APP_STATE_RUNNING && !g_state.stopVideo) while(app_getState() == APP_STATE_RUNNING && !g_state.stopVideo)
{ {
LGMPMessage msg; LGMPMessage msg;
if ((status = lgmpClientProcess(queue, &msg)) != LGMP_OK) if ((status = lgmpClientProcess(queue, &msg)) != LGMP_OK)
@@ -624,11 +624,11 @@ int main_frameThread(void * unused)
} }
if (status == LGMP_ERR_INVALID_SESSION) if (status == LGMP_ERR_INVALID_SESSION)
g_state.state = APP_STATE_RESTART; app_setState(APP_STATE_RESTART);
else else
{ {
DEBUG_ERROR("lgmpClientProcess Failed: %s", lgmpStatusString(status)); DEBUG_ERROR("lgmpClientProcess Failed: %s", lgmpStatusString(status));
g_state.state = APP_STATE_SHUTDOWN; app_setState(APP_STATE_SHUTDOWN);
} }
break; break;
} }
@@ -744,7 +744,7 @@ int main_frameThread(void * unused)
if (error) if (error)
{ {
lgmpClientMessageDone(queue); lgmpClientMessageDone(queue);
g_state.state = APP_STATE_SHUTDOWN; app_setState(APP_STATE_SHUTDOWN);
break; break;
} }
@@ -765,7 +765,7 @@ int main_frameThread(void * unused)
if (!RENDERER(onFrameFormat, lgrFormat)) if (!RENDERER(onFrameFormat, lgrFormat))
{ {
DEBUG_ERROR("renderer failed to configure format"); DEBUG_ERROR("renderer failed to configure format");
g_state.state = APP_STATE_SHUTDOWN; app_setState(APP_STATE_SHUTDOWN);
LG_UNLOCK(g_state.lgrLock); LG_UNLOCK(g_state.lgrLock);
break; break;
} }
@@ -827,7 +827,7 @@ int main_frameThread(void * unused)
if (!dma) if (!dma)
{ {
DEBUG_ERROR("Failed to obtain a free DMA buffer for use"); DEBUG_ERROR("Failed to obtain a free DMA buffer for use");
g_state.state = APP_STATE_SHUTDOWN; app_setState(APP_STATE_SHUTDOWN);
break; break;
} }
@@ -842,7 +842,7 @@ int main_frameThread(void * unused)
if (dma->fd < 0) if (dma->fd < 0)
{ {
DEBUG_ERROR("Failed to get the DMA buffer for the frame"); DEBUG_ERROR("Failed to get the DMA buffer for the frame");
g_state.state = APP_STATE_SHUTDOWN; app_setState(APP_STATE_SHUTDOWN);
break; break;
} }
} }
@@ -873,7 +873,7 @@ int main_frameThread(void * unused)
{ {
lgmpClientMessageDone(queue); lgmpClientMessageDone(queue);
DEBUG_ERROR("renderer on frame returned failure"); DEBUG_ERROR("renderer on frame returned failure");
g_state.state = APP_STATE_SHUTDOWN; app_setState(APP_STATE_SHUTDOWN);
break; break;
} }
@@ -921,7 +921,7 @@ int main_frameThread(void * unused)
RENDERER(onRestart); RENDERER(onRestart);
if (g_state.state != APP_STATE_SHUTDOWN) if (app_getState() != APP_STATE_SHUTDOWN)
{ {
if (!app_useSpiceDisplay(true)) if (!app_useSpiceDisplay(true))
overlaySplash_show(true); overlaySplash_show(true);
@@ -939,7 +939,8 @@ int main_frameThread(void * unused)
static void checkUUID(void) static void checkUUID(void)
{ {
if (!g_state.spiceReady || !g_state.guestUUIDValid) if (!atomic_load_explicit(&g_state.spiceReady, memory_order_acquire) ||
!g_state.guestUUIDValid)
return; return;
if (memcmp(g_state.spiceUUID, g_state.guestUUID, if (memcmp(g_state.spiceUUID, g_state.guestUUID,
@@ -952,13 +953,13 @@ static void checkUUID(void)
"Input will not function until this is corrected."); "Input will not function until this is corrected.");
g_params.useSpiceInput = false; g_params.useSpiceInput = false;
g_state.spiceClose = true; atomic_store_explicit(&g_state.spiceClose, true, memory_order_release);
purespice_disconnect(); purespice_disconnect();
} }
void spiceReady(void) void spiceReady(void)
{ {
g_state.spiceReady = true; atomic_store_explicit(&g_state.spiceReady, true, memory_order_release);
if (atomic_load_explicit(&g_state.spiceDisplayRequested, if (atomic_load_explicit(&g_state.spiceDisplayRequested,
memory_order_acquire)) memory_order_acquire))
app_useSpiceDisplay(true); app_useSpiceDisplay(true);
@@ -1172,7 +1173,7 @@ int spiceThread(void * arg)
} }
// process all spice messages // process all spice messages
while(g_state.state != APP_STATE_SHUTDOWN) while(app_getState() != APP_STATE_SHUTDOWN)
{ {
PSStatus status; PSStatus status;
if ((status = purespice_process(100)) != PS_STATUS_RUN) if ((status = purespice_process(100)) != PS_STATUS_RUN)
@@ -1187,11 +1188,13 @@ int spiceThread(void * arg)
if (g_params.useSpiceInput) if (g_params.useSpiceInput)
{ {
for(int scancode = 0; scancode < KEY_MAX; ++scancode) for(int scancode = 0; scancode < KEY_MAX; ++scancode)
if (g_state.keyDown[scancode]) if (atomic_load_explicit(
&g_state.keyDown[scancode], memory_order_relaxed))
{ {
const uint32_t ps2 = linux_to_ps2[scancode]; const uint32_t ps2 = linux_to_ps2[scancode];
if (ps2 && purespice_keyUp(ps2)) if (ps2 && purespice_keyUp(ps2))
g_state.keyDown[scancode] = false; atomic_store_explicit(
&g_state.keyDown[scancode], false, memory_order_relaxed);
else else
DEBUG_ERROR("Failed to release key %d during SPICE shutdown", DEBUG_ERROR("Failed to release key %d during SPICE shutdown",
scancode); scancode);
@@ -1206,8 +1209,8 @@ end:
// if the connection was disconnected intentionally we don't want to shutdown // if the connection was disconnected intentionally we don't want to shutdown
// so that the user can see the message box and take action // so that the user can see the message box and take action
if (!g_state.spiceClose) if (!atomic_load_explicit(&g_state.spiceClose, memory_order_acquire))
g_state.state = APP_STATE_SHUTDOWN; app_setState(APP_STATE_SHUTDOWN);
lgSignalEvent(e_spice); lgSignalEvent(e_spice);
return 0; return 0;
@@ -1219,10 +1222,10 @@ void intHandler(int sig)
{ {
case SIGINT: case SIGINT:
case SIGTERM: case SIGTERM:
if (g_state.state != APP_STATE_SHUTDOWN) if (app_getState() != APP_STATE_SHUTDOWN)
{ {
DEBUG_INFO("Caught signal, shutting down..."); DEBUG_INFO("Caught signal, shutting down...");
g_state.state = APP_STATE_SHUTDOWN; app_setState(APP_STATE_SHUTDOWN);
} }
else else
{ {
@@ -1451,7 +1454,7 @@ static int lg_run(void)
} }
lgWaitEvent(e_spice, TIMEOUT_INFINITE); lgWaitEvent(e_spice, TIMEOUT_INFINITE);
if (!g_state.spiceReady) if (!atomic_load_explicit(&g_state.spiceReady, memory_order_acquire))
return -1; return -1;
} }
@@ -1567,7 +1570,7 @@ static int lg_run(void)
LGMP_STATUS status; LGMP_STATUS status;
while(g_state.state == APP_STATE_RUNNING) while(app_getState() == APP_STATE_RUNNING)
{ {
if ((status = lgmpClientInit(g_state.shm.mem, g_state.shm.size, &g_state.lgmp)) == LGMP_OK) if ((status = lgmpClientInit(g_state.shm.mem, g_state.shm.size, &g_state.lgmp)) == LGMP_OK)
break; break;
@@ -1597,7 +1600,7 @@ restart:
uint64_t initialSpiceEnable = microtime() + 1000 * 1000; uint64_t initialSpiceEnable = microtime() + 1000 * 1000;
while(g_state.state == APP_STATE_RUNNING) while(app_getState() == APP_STATE_RUNNING)
{ {
if (initialSpiceEnable && microtime() > initialSpiceEnable) if (initialSpiceEnable && microtime() > initialSpiceEnable)
{ {
@@ -1621,7 +1624,7 @@ restart:
return -1; return -1;
} }
while (g_state.state == APP_STATE_RUNNING && while (app_getState() == APP_STATE_RUNNING &&
!atomic_load_explicit(&probe.done, memory_order_acquire)) !atomic_load_explicit(&probe.done, memory_order_acquire))
g_state.ds->wait(100); g_state.ds->wait(100);
@@ -1631,7 +1634,7 @@ restart:
return -1; return -1;
} }
if (g_state.state != APP_STATE_RUNNING) if (app_getState() != APP_STATE_RUNNING)
return -1; return -1;
status = probe.status; status = probe.status;
@@ -1706,7 +1709,7 @@ restart:
return -1; return -1;
} }
if (g_state.state != APP_STATE_RUNNING) if (app_getState() != APP_STATE_RUNNING)
return -1; return -1;
// dont show warnings again after the first successful startup // dont show warnings again after the first successful startup
@@ -1718,7 +1721,7 @@ restart:
static bool alertsDone = false; static bool alertsDone = false;
if (alertsDone) if (alertsDone)
{ {
if(g_state.state == APP_STATE_RUNNING) if (app_getState() == APP_STATE_RUNNING)
g_state.ds->wait(1000); g_state.ds->wait(1000);
continue; continue;
} }
@@ -1752,7 +1755,7 @@ restart:
DEBUG_INFO("Waiting for you to upgrade the host application"); DEBUG_INFO("Waiting for you to upgrade the host application");
alertsDone = true; alertsDone = true;
if(g_state.state == APP_STATE_RUNNING) if (app_getState() == APP_STATE_RUNNING)
g_state.ds->wait(1000); g_state.ds->wait(1000);
continue; continue;
@@ -1761,7 +1764,7 @@ restart:
break; break;
} }
if(g_state.state != APP_STATE_RUNNING) if (app_getState() != APP_STATE_RUNNING)
return -1; return -1;
/* close any informational message boxes from above as we now connected /* close any informational message boxes from above as we now connected
@@ -1897,7 +1900,8 @@ restart:
g_state.guestOS = osInfo->os; g_state.guestOS = osInfo->os;
if (g_state.spiceReady && g_params.useSpiceInput) if (atomic_load_explicit(&g_state.spiceReady, memory_order_acquire) &&
g_params.useSpiceInput)
keybind_spiceRegister(); keybind_spiceRegister();
break; break;
} }
@@ -1913,10 +1917,11 @@ restart:
checkUUID(); checkUUID();
if (g_state.state == APP_STATE_RUNNING) if (app_getState() == APP_STATE_RUNNING)
{ {
DEBUG_INFO("Starting session"); DEBUG_INFO("Starting session");
g_state.lgHostConnected = true; atomic_store_explicit(
&g_state.lgHostConnected, true, memory_order_release);
} }
g_state.kvmfrFeatures = udata->features; g_state.kvmfrFeatures = udata->features;
@@ -1928,20 +1933,21 @@ restart:
return -1; return -1;
} }
while(likely(g_state.state == APP_STATE_RUNNING)) while(likely(app_getState() == APP_STATE_RUNNING))
{ {
if (unlikely(!lgmpClientSessionValid(g_state.lgmp))) if (unlikely(!lgmpClientSessionValid(g_state.lgmp)))
{ {
g_state.lgHostConnected = false; atomic_store_explicit(
&g_state.lgHostConnected, false, memory_order_release);
DEBUG_INFO("Waiting for the host to restart..."); DEBUG_INFO("Waiting for the host to restart...");
g_state.state = APP_STATE_RESTART; app_setState(APP_STATE_RESTART);
break; break;
} }
lgMessage_process(); lgMessage_process();
g_state.ds->wait(100); g_state.ds->wait(100);
} }
if (g_state.state == APP_STATE_RESTART) if (app_getState() == APP_STATE_RESTART)
{ {
lgSignalEvent(e_startup); lgSignalEvent(e_startup);
lgSignalEvent(g_state.frameEvent); lgSignalEvent(g_state.frameEvent);
@@ -1949,7 +1955,7 @@ restart:
core_stopFrameThread(); core_stopFrameThread();
core_stopCursorThread(); core_stopCursorThread();
g_state.state = APP_STATE_RUNNING; app_setState(APP_STATE_RUNNING);
lgInit(); lgInit();
goto restart; goto restart;
} }
@@ -1960,7 +1966,7 @@ restart:
static void lg_shutdown(void) static void lg_shutdown(void)
{ {
g_state.state = APP_STATE_SHUTDOWN; app_setState(APP_STATE_SHUTDOWN);
if (t_spice) if (t_spice)
lgJoinThread(t_spice, NULL); lgJoinThread(t_spice, NULL);

View File

@@ -55,7 +55,7 @@ enum MicDefaultState {
struct AppState struct AppState
{ {
enum RunState state; _Atomic(enum RunState) state;
ImGuiIO * io; ImGuiIO * io;
ImGuiStyle * style; ImGuiStyle * style;
@@ -79,7 +79,7 @@ struct AppState
bool jitRender; bool jitRender;
uint8_t spiceUUID[16]; uint8_t spiceUUID[16];
bool spiceReady; atomic_bool spiceReady;
atomic_bool spiceDisplayRequested; atomic_bool spiceDisplayRequested;
atomic_bool spiceDisplayActive; atomic_bool spiceDisplayActive;
atomic_bool spiceDisplayTransition; atomic_bool spiceDisplayTransition;
@@ -89,7 +89,7 @@ struct AppState
bool guestUUIDValid; bool guestUUIDValid;
KVMFROS guestOS; KVMFROS guestOS;
bool lgHostConnected; atomic_bool lgHostConnected;
bool stopVideo; bool stopVideo;
bool ignoreInput; bool ignoreInput;
@@ -98,7 +98,7 @@ struct AppState
int escapeAction; int escapeAction;
bool escapeHelp; bool escapeHelp;
struct ll * bindings; struct ll * bindings;
bool keyDown[KEY_MAX]; atomic_bool keyDown[KEY_MAX];
bool haveSrcSize; bool haveSrcSize;
struct Point windowPos; struct Point windowPos;
@@ -112,7 +112,7 @@ struct AppState
LG_RendererRect dstRect; LG_RendererRect dstRect;
bool posInfoValid; bool posInfoValid;
bool alignToGuest; bool alignToGuest;
bool spiceClose; atomic_bool spiceClose;
atomic_uint_least64_t shaderMousePosition; atomic_uint_least64_t shaderMousePosition;
atomic_uint_least32_t shaderMouseState; atomic_uint_least32_t shaderMouseState;
@@ -342,6 +342,16 @@ extern struct AppState g_state;
extern struct CursorState g_cursor; extern struct CursorState g_cursor;
extern struct AppParams g_params; extern struct AppParams g_params;
static inline enum RunState app_getState(void)
{
return atomic_load_explicit(&g_state.state, memory_order_acquire);
}
static inline void app_setState(enum RunState state)
{
atomic_store_explicit(&g_state.state, state, memory_order_release);
}
int main_cursorThread(void * unused); int main_cursorThread(void * unused);
int main_frameThread(void * unused); int main_frameThread(void * unused);