[client] lgmp: fix timeout due to improper handling of pause/resume

This commit is contained in:
Geoffrey McRae
2026-07-31 12:57:09 +10:00
parent 33c81d2cf5
commit 9417a71264
3 changed files with 66 additions and 18 deletions

View File

@@ -201,11 +201,17 @@ typedef struct LG_TransportOps
LG_TransportStatus (*nextFrame)(LG_Transport * transport, bool useDMA, LG_TransportStatus (*nextFrame)(LG_Transport * transport, bool useDMA,
LG_TransportFrame * frame); LG_TransportFrame * frame);
void (*releaseFrame)(LG_Transport * transport, LG_TransportFrame * frame); void (*releaseFrame)(LG_Transport * transport, LG_TransportFrame * frame);
/* Called by the frame consumer as it exits. A backend may release transient
* stream resources; nextFrame must reacquire them when the consumer restarts. */
void (*stopFrame)(LG_Transport * transport);
LG_TransportStatus (*nextPointer)(LG_Transport * transport, LG_TransportStatus (*nextPointer)(LG_Transport * transport,
LG_TransportPointer * pointer); LG_TransportPointer * pointer);
void (*releasePointer)(LG_Transport * transport, void (*releasePointer)(LG_Transport * transport,
LG_TransportPointer * pointer); LG_TransportPointer * pointer);
/* Called by the pointer consumer as it exits. A backend may release transient
* stream resources; nextPointer must reacquire them when the consumer restarts. */
void (*stopPointer)(LG_Transport * transport);
LG_TransportStatus (*sendControl)(LG_Transport * transport, LG_TransportStatus (*sendControl)(LG_Transport * transport,
const LG_TransportControl * control, LG_TransportControlToken * token); const LG_TransportControl * control, LG_TransportControlToken * token);

View File

@@ -569,6 +569,9 @@ int main_cursorThread(void * unused)
g_state.transportOps->releasePointer(g_state.transport, &pointer); g_state.transportOps->releasePointer(g_state.transport, &pointer);
} }
if (g_state.transportOps->stopPointer)
g_state.transportOps->stopPointer(g_state.transport);
return 0; return 0;
} }
@@ -583,7 +586,11 @@ int main_frameThread(void * unused)
lgWaitEvent(e_startup, TIMEOUT_INFINITE); lgWaitEvent(e_startup, TIMEOUT_INFINITE);
if (app_getState() != APP_STATE_RUNNING) if (app_getState() != APP_STATE_RUNNING)
{
if (g_state.transportOps->stopFrame)
g_state.transportOps->stopFrame(g_state.transport);
return 0; return 0;
}
while(app_getState() == APP_STATE_RUNNING && !g_state.stopVideo) while(app_getState() == APP_STATE_RUNNING && !g_state.stopVideo)
{ {
@@ -813,6 +820,9 @@ int main_frameThread(void * unused)
app_useSpiceDisplay(false); app_useSpiceDisplay(false);
} }
if (g_state.transportOps->stopFrame)
g_state.transportOps->stopFrame(g_state.transport);
RENDERER(onRestart); RENDERER(onRestart);
if (app_getState() != APP_STATE_SHUTDOWN) if (app_getState() != APP_STATE_SHUTDOWN)

View File

@@ -204,20 +204,47 @@ static bool lgmp_create(LG_Transport ** result)
return true; return true;
} }
static void lgmp_closeQueues(struct LG_Transport * this) static void lgmp_stopFrame(struct LG_Transport * this)
{ {
if (this->framePending && this->frameQueue) if (this->framePending && this->frameQueue)
{ {
lgmpClientMessageDone(this->frameQueue); const LGMP_STATUS status = lgmpClientMessageDone(this->frameQueue);
this->framePending = false; if (status != LGMP_OK)
DEBUG_WARN("Failed to release pending LGMP frame: %s",
lgmpStatusString(status));
}
this->framePending = false;
LGMP_STATUS status = lgmpClientUnsubscribe(&this->frameQueue);
if (status != LGMP_OK)
{
DEBUG_WARN("Failed to unsubscribe from the LGMP frame queue: %s",
lgmpStatusString(status));
this->frameQueue = NULL;
} }
lgmpClientUnsubscribe(&this->frameQueue);
this->frameSerial = 0;
this->formatValid = false;
}
static void lgmp_stopPointer(struct LG_Transport * this)
{
LG_LOCK(this->pointerLock); LG_LOCK(this->pointerLock);
lgmpClientUnsubscribe(&this->pointerQueue); const LGMP_STATUS status = lgmpClientUnsubscribe(&this->pointerQueue);
if (status != LGMP_OK)
{
DEBUG_WARN("Failed to unsubscribe from the LGMP pointer queue: %s",
lgmpStatusString(status));
this->pointerQueue = NULL;
}
LG_UNLOCK(this->pointerLock); LG_UNLOCK(this->pointerLock);
} }
static void lgmp_closeQueues(struct LG_Transport * this)
{
lgmp_stopFrame(this);
lgmp_stopPointer(this);
}
static void lgmp_closeDMA(struct LG_Transport * this) static void lgmp_closeDMA(struct LG_Transport * this)
{ {
for (unsigned i = 0; i < LGMP_Q_FRAME_LEN; ++i) for (unsigned i = 0; i < LGMP_Q_FRAME_LEN; ++i)
@@ -358,9 +385,7 @@ static void lgmp_disconnect(LG_Transport * this)
{ {
lgmp_closeQueues(this); lgmp_closeQueues(this);
lgmp_closeDMA(this); lgmp_closeDMA(this);
this->connected = false; this->connected = false;
this->frameSerial = 0;
this->formatValid = false;
} }
static bool lgmp_sessionValid(LG_Transport * this) static bool lgmp_sessionValid(LG_Transport * this)
@@ -389,10 +414,13 @@ static LG_TransportStatus lgmp_subscribe(PLGMPClient client, uint32_t id,
if (*queue) if (*queue)
return LG_TRANSPORT_OK; return LG_TRANSPORT_OK;
LGMP_STATUS status = lgmpClientSubscribe(client, id, queue); PLGMPClientQueue subscribed = NULL;
LGMP_STATUS status = lgmpClientSubscribe(client, id, &subscribed);
switch (status) switch (status)
{ {
case LGMP_OK: return LG_TRANSPORT_OK; case LGMP_OK:
*queue = subscribed;
return LG_TRANSPORT_OK;
case LGMP_ERR_NO_SUCH_QUEUE: return LG_TRANSPORT_TIMEOUT; case LGMP_ERR_NO_SUCH_QUEUE: return LG_TRANSPORT_TIMEOUT;
case LGMP_ERR_INVALID_SESSION: return LG_TRANSPORT_DISCONNECTED; case LGMP_ERR_INVALID_SESSION: return LG_TRANSPORT_DISCONNECTED;
default: default:
@@ -594,10 +622,16 @@ static LG_TransportStatus lgmp_nextPointer(LG_Transport * this,
uint32_t pointerFlags = 0; uint32_t pointerFlags = 0;
size_t shapeSize = 0; size_t shapeSize = 0;
size_t transformSize = 0; size_t transformSize = 0;
LG_LOCK(this->pointerLock); LG_TransportStatus status = LG_TRANSPORT_OK;
LG_TransportStatus status = lgmp_subscribe(this->client, LGMP_Q_POINTER, if (!this->pointerQueue)
&this->pointerQueue); {
LG_UNLOCK(this->pointerLock); LG_LOCK(this->pointerLock);
status = lgmp_subscribe(this->client, LGMP_Q_POINTER,
&this->pointerQueue);
LG_UNLOCK(this->pointerLock);
if (status == LG_TRANSPORT_TIMEOUT)
usleep(1000);
}
if (status == LG_TRANSPORT_OK) if (status == LG_TRANSPORT_OK)
{ {
LGMPMessage message; LGMPMessage message;
@@ -649,11 +683,7 @@ static LG_TransportStatus lgmp_nextPointer(LG_Transport * this,
} }
} }
if (status != LG_TRANSPORT_OK) if (status != LG_TRANSPORT_OK)
{
if (status == LG_TRANSPORT_TIMEOUT)
usleep(1000);
return status; return status;
}
const KVMFRCursor * cursor = (const KVMFRCursor *)this->pointerData; const KVMFRCursor * cursor = (const KVMFRCursor *)this->pointerData;
memset(result, 0, sizeof(*result)); memset(result, 0, sizeof(*result));
@@ -771,8 +801,10 @@ const LG_TransportOps LGT_LGMP =
.detachRenderer = lgmp_detachRenderer, .detachRenderer = lgmp_detachRenderer,
.nextFrame = lgmp_nextFrame, .nextFrame = lgmp_nextFrame,
.releaseFrame = lgmp_releaseFrame, .releaseFrame = lgmp_releaseFrame,
.stopFrame = lgmp_stopFrame,
.nextPointer = lgmp_nextPointer, .nextPointer = lgmp_nextPointer,
.releasePointer = lgmp_releasePointer, .releasePointer = lgmp_releasePointer,
.stopPointer = lgmp_stopPointer,
.sendControl = lgmp_sendControl, .sendControl = lgmp_sendControl,
.controlStatus = lgmp_controlStatus, .controlStatus = lgmp_controlStatus,
}; };