[client] lgmp: serialize stale pointer recovery

Clear timed-out pointer subscriptions under pointerLock so control sends
cannot race a cached queue handle becoming NULL.
This commit is contained in:
Geoffrey McRae
2026-08-06 14:49:02 +10:00
parent 05f3b39b43
commit 92f46f693f

View File

@@ -651,20 +651,30 @@ static LG_TransportStatus lgmp_doneFrameMessage(
return LG_TRANSPORT_ERROR; return LG_TRANSPORT_ERROR;
} }
static LG_TransportStatus lgmp_donePointerMessage(LG_Transport * this) static void lgmp_clearPointerQueue(LG_Transport * this,
PLGMPClientQueue expected)
{ {
const LGMP_STATUS status = lgmpClientMessageDone(this->pointerQueue); LG_LOCK(this->pointerLock);
if (this->pointerQueue == expected)
this->pointerQueue = NULL;
LG_UNLOCK(this->pointerLock);
}
static LG_TransportStatus lgmp_donePointerMessage(LG_Transport * this,
PLGMPClientQueue queue)
{
const LGMP_STATUS status = lgmpClientMessageDone(queue);
if (status == LGMP_OK) if (status == LGMP_OK)
return LG_TRANSPORT_OK; return LG_TRANSPORT_OK;
if (status == LGMP_ERR_INVALID_SESSION) if (status == LGMP_ERR_INVALID_SESSION)
{ {
this->pointerQueue = NULL; lgmp_clearPointerQueue(this, queue);
return LG_TRANSPORT_DISCONNECTED; return LG_TRANSPORT_DISCONNECTED;
} }
if (status == LGMP_ERR_QUEUE_TIMEOUT || if (status == LGMP_ERR_QUEUE_TIMEOUT ||
status == LGMP_ERR_QUEUE_UNSUBSCRIBED) status == LGMP_ERR_QUEUE_UNSUBSCRIBED)
{ {
this->pointerQueue = NULL; lgmp_clearPointerQueue(this, queue);
return LG_TRANSPORT_OK; return LG_TRANSPORT_OK;
} }
@@ -1090,29 +1100,35 @@ static LG_TransportStatus lgmp_nextPointer(LG_Transport * this,
if (!this->connected) if (!this->connected)
return LG_TRANSPORT_DISCONNECTED; return LG_TRANSPORT_DISCONNECTED;
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_TransportStatus status = LG_TRANSPORT_OK; LG_TransportStatus status = LG_TRANSPORT_OK;
PLGMPClientQueue pointerQueue;
LG_LOCK(this->pointerLock);
if (!this->pointerQueue) if (!this->pointerQueue)
{ {
LG_LOCK(this->pointerLock);
status = lgmp_subscribe(this->client, LGMP_Q_POINTER, status = lgmp_subscribe(this->client, LGMP_Q_POINTER,
&this->pointerQueue); &this->pointerQueue);
LG_UNLOCK(this->pointerLock);
if (status == LG_TRANSPORT_TIMEOUT)
usleep(1000);
} }
pointerQueue = 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;
status = lgmp_process(&this->pointerQueue, this->cursorPollInterval, PLGMPClientQueue processedQueue = pointerQueue;
status = lgmp_process(&processedQueue, this->cursorPollInterval,
&message); &message);
if (!processedQueue)
lgmp_clearPointerQueue(this, pointerQueue);
if (status == LG_TRANSPORT_OK) if (status == LG_TRANSPORT_OK)
{ {
if (message.size < sizeof(KVMFRCursor)) if (message.size < sizeof(KVMFRCursor))
{ {
const LG_TransportStatus done = lgmp_donePointerMessage(this); const LG_TransportStatus done =
lgmp_donePointerMessage(this, pointerQueue);
status = done == LG_TRANSPORT_DISCONNECTED ? status = done == LG_TRANSPORT_DISCONNECTED ?
done : LG_TRANSPORT_ERROR; done : LG_TRANSPORT_ERROR;
} }
@@ -1127,7 +1143,8 @@ static LG_TransportStatus lgmp_nextPointer(LG_Transport * this,
if (shapeSize > message.size - sizeof(*cursor) || if (shapeSize > message.size - sizeof(*cursor) ||
transformSize > message.size - sizeof(*cursor) - shapeSize) transformSize > message.size - sizeof(*cursor) - shapeSize)
{ {
const LG_TransportStatus done = lgmp_donePointerMessage(this); const LG_TransportStatus done =
lgmp_donePointerMessage(this, pointerQueue);
status = done == LG_TRANSPORT_DISCONNECTED ? status = done == LG_TRANSPORT_DISCONNECTED ?
done : LG_TRANSPORT_ERROR; done : LG_TRANSPORT_ERROR;
} }
@@ -1150,7 +1167,8 @@ static LG_TransportStatus lgmp_nextPointer(LG_Transport * this,
memcpy(this->pointerData, message.mem, needed); memcpy(this->pointerData, message.mem, needed);
pointerFlags = (uint32_t)message.udata; pointerFlags = (uint32_t)message.udata;
} }
const LG_TransportStatus done = lgmp_donePointerMessage(this); const LG_TransportStatus done =
lgmp_donePointerMessage(this, pointerQueue);
if (status == LG_TRANSPORT_OK) if (status == LG_TRANSPORT_OK)
status = done; status = done;
} }