From c11090a4cf071eed7f2bb4d6b78de4ce107e4f53 Mon Sep 17 00:00:00 2001 From: Adam Honse Date: Sun, 17 May 2026 15:01:54 -0500 Subject: [PATCH] Add another thread in NetworkClient for handling ProfileManager requests outside of the main listener thread, to avoid deadlocking the waiting receivers --- NetworkClient.cpp | 102 +++++++++++++++++++++++++++++++++++++++------- NetworkClient.h | 19 +++++++++ NetworkServer.cpp | 15 ++++++- 3 files changed, 120 insertions(+), 16 deletions(-) diff --git a/NetworkClient.cpp b/NetworkClient.cpp index 33a3e89e8..f09fdc59f 100644 --- a/NetworkClient.cpp +++ b/NetworkClient.cpp @@ -242,6 +242,16 @@ void NetworkClient::StartClient() \*-----------------------------------------------------*/ ConnectionThread = new std::thread(&NetworkClient::ConnectionThreadFunction, this); + /*-----------------------------------------------------*\ + | Start the ProfileManager listen thread | + \*-----------------------------------------------------*/ + profilemanager_thread = new NetworkClientListenerThread; + + profilemanager_thread->id = 0; + profilemanager_thread->index = 0; + profilemanager_thread->online = true; + profilemanager_thread->thread = new std::thread(&NetworkClient::ProfileManagerListenThread, this, profilemanager_thread); + /*-----------------------------------------------------*\ | Client info has changed, call the callbacks | \*-----------------------------------------------------*/ @@ -278,6 +288,19 @@ void NetworkClient::StopClient() ListenThread = nullptr; } + /*-----------------------------------------------------*\ + | Close the ProfileManager listen thread | + \*-----------------------------------------------------*/ + if(profilemanager_thread->thread) + { + profilemanager_thread->online = false; + profilemanager_thread->start_cv.notify_all(); + profilemanager_thread->thread->join(); + delete profilemanager_thread->thread; + profilemanager_thread->thread = nullptr; + delete profilemanager_thread; + } + /*-----------------------------------------------------*\ | Close the connection thread | \*-----------------------------------------------------*/ @@ -1027,6 +1050,51 @@ void NetworkClient::SignalNetworkClientUpdate(unsigned int update_reason) NetworkClientCallbackMutex.unlock(); } +void NetworkClient::ProfileManagerListenThread(NetworkClientListenerThread* this_thread) +{ + while(this_thread->online == true) + { + std::unique_lock start_lock(this_thread->start_mutex); + this_thread->start_cv.wait(start_lock); + + while(this_thread->queue.size() > 0) + { + NetworkClientListenerThreadQueueEntry queue_entry; + + this_thread->queue_mutex.lock(); + queue_entry = this_thread->queue.front(); + this_thread->queue.pop(); + this_thread->queue_mutex.unlock(); + + switch(queue_entry.header.pkt_id) + { + case NET_PACKET_ID_PROFILEMANAGER_ACTIVE_PROFILE_CHANGED: + ProcessRequest_ProfileManager_ActiveProfileChanged(queue_entry.header.pkt_size, queue_entry.data); + break; + + case NET_PACKET_ID_PROFILEMANAGER_PROFILE_LOADED: + ProcessRequest_ProfileManager_ProfileLoaded(queue_entry.header.pkt_size, queue_entry.data); + break; + + case NET_PACKET_ID_PROFILEMANAGER_PROFILE_ABOUT_TO_LOAD: + ProcessRequest_ProfileManager_ProfileAboutToLoad(); + break; + + case NET_PACKET_ID_PROFILEMANAGER_GET_PROFILE_LIST: + case NET_PACKET_ID_PROFILEMANAGER_PROFILE_LIST_UPDATED: + ProcessRequest_ProfileManager_ProfileListUpdated(queue_entry.header.pkt_size, queue_entry.data); + break; + + case NET_PACKET_ID_RGBCONTROLLER_SIGNALUPDATE: + ProcessRequest_RGBController_SignalUpdate(queue_entry.header.pkt_size, queue_entry.data, queue_entry.header.pkt_dev_id); + break; + } + + delete[] queue_entry.data; + } + } +} + /*---------------------------------------------------------*\ | Client thread functions | \*---------------------------------------------------------*/ @@ -1426,25 +1494,29 @@ void NetworkClient::ListenThreadFunction() } break; - case NET_PACKET_ID_PROFILEMANAGER_ACTIVE_PROFILE_CHANGED: - ProcessRequest_ProfileManager_ActiveProfileChanged(header.pkt_size, data); - break; - - case NET_PACKET_ID_PROFILEMANAGER_PROFILE_LOADED: - ProcessRequest_ProfileManager_ProfileLoaded(header.pkt_size, data); - break; - + /*-------------------------------------------------*\ + | ProfileManager functions are handled in a | + | separate thread, queue the messages | + \*-------------------------------------------------*/ case NET_PACKET_ID_PROFILEMANAGER_PROFILE_ABOUT_TO_LOAD: - ProcessRequest_ProfileManager_ProfileAboutToLoad(); - break; - + case NET_PACKET_ID_PROFILEMANAGER_ACTIVE_PROFILE_CHANGED: + case NET_PACKET_ID_PROFILEMANAGER_PROFILE_LOADED: case NET_PACKET_ID_PROFILEMANAGER_GET_PROFILE_LIST: case NET_PACKET_ID_PROFILEMANAGER_PROFILE_LIST_UPDATED: - ProcessRequest_ProfileManager_ProfileListUpdated(header.pkt_size, data); - break; - case NET_PACKET_ID_RGBCONTROLLER_SIGNALUPDATE: - ProcessRequest_RGBController_SignalUpdate(header.pkt_size, data, header.pkt_dev_id); + { + profilemanager_thread->queue_mutex.lock(); + + NetworkClientListenerThreadQueueEntry new_entry; + new_entry.data = data; + new_entry.header = header; + + profilemanager_thread->queue.push(new_entry); + profilemanager_thread->queue_mutex.unlock(); + profilemanager_thread->start_cv.notify_all(); + + delete_data = false; + } break; } diff --git a/NetworkClient.h b/NetworkClient.h index ea1664326..927e8386c 100644 --- a/NetworkClient.h +++ b/NetworkClient.h @@ -13,6 +13,7 @@ #include #include +#include #include #include #include "i2c_smbus.h" @@ -44,7 +45,23 @@ enum NETWORKCLIENT_UPDATE_REASON_PROFILEMANAGER_ACTIVE_PROFILE_CHANGED, /* Active profile changed */ }; +typedef struct +{ + NetPacketHeader header; + unsigned char* data; +} NetworkClientListenerThreadQueueEntry; +typedef struct +{ + unsigned int id; + unsigned int index; + std::queue queue; + std::mutex queue_mutex; + std::mutex start_mutex; + std::condition_variable start_cv; + std::thread* thread; + std::atomic online; +} NetworkClientListenerThread; class NetworkClient { @@ -206,6 +223,7 @@ private: std::condition_variable connection_cv; std::thread * ConnectionThread; std::thread * ListenThread; + NetworkClientListenerThread* profilemanager_thread; /*-----------------------------------------------------*\ | Callbacks | @@ -237,6 +255,7 @@ private: \*-----------------------------------------------------*/ void ConnectionThreadFunction(); void ListenThreadFunction(); + void ProfileManagerListenThread(NetworkClientListenerThread* this_thread); /*-----------------------------------------------------*\ | Private Client functions | diff --git a/NetworkServer.cpp b/NetworkServer.cpp index b7f0f0289..9ba252424 100644 --- a/NetworkServer.cpp +++ b/NetworkServer.cpp @@ -563,6 +563,19 @@ void NetworkServer::StopServer() socket_count = 0; + /*-----------------------------------------------------*\ + | Close the ProfileManager listen thread | + \*-----------------------------------------------------*/ + if(profilemanager_thread->thread) + { + profilemanager_thread->online = false; + profilemanager_thread->start_cv.notify_all(); + profilemanager_thread->thread->join(); + delete profilemanager_thread->thread; + profilemanager_thread->thread = nullptr; + delete profilemanager_thread; + } + /*-----------------------------------------------------*\ | Client info has changed, call the callbacks | \*-----------------------------------------------------*/ @@ -1066,7 +1079,7 @@ void NetworkServer::ControllerListenThread(NetworkServerControllerThread* this_t void NetworkServer::ProfileManagerListenThread(NetworkServerControllerThread* this_thread) { - while(this_thread->online == true) + while(this_thread->online == true) { std::unique_lock start_lock(this_thread->start_mutex); this_thread->start_cv.wait(start_lock);