Skip to content

Commit 661efd1

Browse files
thiseignif
authored andcommitted
[host] app: fix app state race in lgmpTimer thread
While resuming from hibernation lgmpTimer may transition app.state to APP_STATE_REINIT_LGMP. Sometimes the transition is lost if the app_main processing loop also changes app.state simultaneously. This seems to occur frequently with the hibernation use case. Separate lgmp timer state into its own enum. Move resulting app.state transitions to the app_main loop so they are serialized.
1 parent f6094de commit 661efd1

File tree

1 file changed

+26
-11
lines changed

1 file changed

+26
-11
lines changed

host/src/app.c

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,16 @@ enum AppState
6969
APP_STATE_RUNNING,
7070
APP_STATE_IDLE,
7171
APP_STATE_TRANSITION_TO_IDLE,
72-
APP_STATE_REINIT_LGMP,
7372
APP_STATE_SHUTDOWN
7473
};
7574

75+
enum LGMPTimerState
76+
{
77+
LGMP_TIMER_STATE_OK,
78+
LGMP_TIMER_STATE_CORRUPTED,
79+
LGMP_TIMER_STATE_FAULTED
80+
};
81+
7682
struct app
7783
{
7884
int exitcode;
@@ -105,7 +111,8 @@ struct app
105111
CaptureInterface * iface;
106112
bool captureStarted;
107113

108-
enum AppState state, lastState;
114+
enum AppState state;
115+
enum LGMPTimerState lgmpTimerState;
109116
LGTimer * lgmpTimer;
110117
LGThread * frameThread;
111118
bool threadsStarted;
@@ -162,8 +169,7 @@ inline static void setAppState(enum AppState state)
162169
{
163170
if (app.state == APP_STATE_SHUTDOWN)
164171
return;
165-
app.lastState = app.state;
166-
app.state = state;
172+
app.state = state;
167173
}
168174

169175
static bool lgmpTimer(void * opaque)
@@ -176,12 +182,12 @@ static bool lgmpTimer(void * opaque)
176182
{
177183
DEBUG_ERROR("LGMP reported the shared memory has been corrrupted, "
178184
"attempting to recover");
179-
setAppState(APP_STATE_REINIT_LGMP);
185+
atomic_store(&app.lgmpTimerState, LGMP_TIMER_STATE_CORRUPTED);
180186
return false;
181187
}
182188

183189
DEBUG_ERROR("lgmpHostProcess Failed: %s", lgmpStatusString(status));
184-
setAppState(APP_STATE_SHUTDOWN);
190+
atomic_store(&app.lgmpTimerState, LGMP_TIMER_STATE_FAULTED);
185191
return false;
186192
}
187193

@@ -785,6 +791,7 @@ static bool lgmpSetup(struct IVSHMEM * shmDev)
785791
app.frameBuffer[i] = (FrameBuffer *)(((uint8_t*)app.frame[i]) + alignOffset);
786792
}
787793

794+
atomic_store(&app.lgmpTimerState, LGMP_TIMER_STATE_OK);
788795
if (!lgCreateTimer(10, lgmpTimer, NULL, &app.lgmpTimer))
789796
{
790797
DEBUG_ERROR("Failed to create the LGMP timer");
@@ -811,8 +818,7 @@ int app_main(int argc, char * argv[])
811818
// make sure rng is actually seeded for LGMP
812819
srand((unsigned)time(NULL));
813820

814-
app.lastState = APP_STATE_RUNNING;
815-
app.state = APP_STATE_RUNNING;
821+
app.state = APP_STATE_RUNNING;
816822
ivshmemOptionsInit();
817823

818824
// register capture interface options
@@ -954,16 +960,25 @@ int app_main(int argc, char * argv[])
954960

955961
do
956962
{
957-
switch(app.state)
963+
switch(atomic_load(&app.lgmpTimerState))
958964
{
959-
case APP_STATE_REINIT_LGMP:
965+
case LGMP_TIMER_STATE_OK:
966+
break;
967+
968+
case LGMP_TIMER_STATE_CORRUPTED:
960969
DEBUG_INFO("Performing LGMP reinitialization");
961970
lgmpShutdown();
962-
setAppState(app.lastState);
963971
if (!lgmpSetup(&shmDev))
964972
goto fail_lgmp;
965973
break;
966974

975+
case LGMP_TIMER_STATE_FAULTED:
976+
setAppState(APP_STATE_SHUTDOWN);
977+
break;
978+
}
979+
980+
switch(app.state)
981+
{
967982
case APP_STATE_IDLE:
968983
// if there are no clients subscribed, just remain idle
969984
if (!lgmpHostQueueHasSubs(app.pointerQueue) &&

0 commit comments

Comments
 (0)