mirror of
https://github.com/moonlight-stream/moonlight-common-c.git
synced 2025-08-18 09:25:49 +00:00
Run the client's connectionTerminated() callback on a separate thread to avoid deadlocking if LiStopConnection() is invoked from the callback
This commit is contained in:
parent
a41c064cab
commit
b9597d696a
@ -4,6 +4,8 @@
|
|||||||
static int stage = STAGE_NONE;
|
static int stage = STAGE_NONE;
|
||||||
static ConnListenerConnectionTerminated originalTerminationCallback;
|
static ConnListenerConnectionTerminated originalTerminationCallback;
|
||||||
static int alreadyTerminated;
|
static int alreadyTerminated;
|
||||||
|
static PLT_THREAD terminationCallbackThread;
|
||||||
|
static long terminationCallbackErrorCode;
|
||||||
|
|
||||||
// Common globals
|
// Common globals
|
||||||
struct sockaddr_storage RemoteAddr;
|
struct sockaddr_storage RemoteAddr;
|
||||||
@ -107,15 +109,39 @@ void LiStopConnection(void) {
|
|||||||
LC_ASSERT(stage == STAGE_NONE);
|
LC_ASSERT(stage == STAGE_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void terminationCallbackThreadFunc(void* context)
|
||||||
|
{
|
||||||
|
// Invoke the client's termination callback
|
||||||
|
originalTerminationCallback(terminationCallbackErrorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This shim callback runs the client's connectionTerminated() callback on a
|
||||||
|
// separate thread. This is neccessary because other internal threads directly
|
||||||
|
// invoke this callback. That can result in a deadlock if the client
|
||||||
|
// calls LiStopConnection() in the callback when the cleanup code
|
||||||
|
// attempts to join the thread that the termination callback (and LiStopConnection)
|
||||||
|
// is running on.
|
||||||
static void ClInternalConnectionTerminated(long errorCode)
|
static void ClInternalConnectionTerminated(long errorCode)
|
||||||
{
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
// Avoid recursion and issuing multiple callbacks
|
// Avoid recursion and issuing multiple callbacks
|
||||||
if (alreadyTerminated) {
|
if (alreadyTerminated) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
alreadyTerminated = 1;
|
alreadyTerminated = 1;
|
||||||
originalTerminationCallback(errorCode);
|
|
||||||
|
// Invoke the termination callback on a separate thread
|
||||||
|
err = PltCreateThread(terminationCallbackThreadFunc, NULL, &terminationCallbackThread);
|
||||||
|
if (err != 0) {
|
||||||
|
// Nothing we can safely do here, so we'll just assert on debug builds
|
||||||
|
Limelog("Failed to create termination thread: %d\n", err);
|
||||||
|
LC_ASSERT(err == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the thread handle since we can never wait on it
|
||||||
|
PltCloseThread(&terminationCallbackThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int resolveHostName(const char *host)
|
static int resolveHostName(const char *host)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user