mirror of
https://github.com/CalcProgrammer1/OpenRGB.git
synced 2026-09-13 05:39:07 -04:00
Tear down lost and closed client connections safely
When a connection dropped, the listener thread deleted all of that server's controllers immediately, before anything else was notified, so the GUI, ResourceManager, and plugins kept dereferencing freed controllers. Clicking Disconnect had the same problem and also ran the teardown inline on the GUI thread, where UpdateDeviceList's DEVICE_LIST_UPDATED is a BlockingQueuedConnection back to that thread, so the device pages were not torn down before the controllers were freed and a later queued onDetectionEnded dereferenced them. Neither path frees controllers inline now. NetworkClient moves them to an orphaned list and a dedicated teardown thread frees them: plugins are warned first, then the same DETECTION_STARTED, UpdateDeviceList, DETECTION_COMPLETE sequence a rescan runs tears down the device pages that still reference the controllers, and only then are they freed, so a controller always outlives its page. Both the connection-loss path and the disconnect button queue to that thread, so the blocking handler runs on the GUI thread while the controllers are still alive, and StopClient's join stays off the GUI and listener threads.
This commit is contained in:
1 parent
09a5b414b6
commit
fb0e4f3ad9
4 files changed
+246
-28
No files matched your search
+56
-8
@@ -106,6 +106,20 @@ NetworkClient::NetworkClient()
|
||||
NetworkClient::~NetworkClient()
|
||||
{
|
||||
StopClient();
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Free the controllers set aside by StopClient, plus |
|
||||
| any left behind by a listener that never ran |
|
||||
\*-----------------------------------------------------*/
|
||||
ControllerListMutex.lock();
|
||||
|
||||
orphaned_controllers.insert(orphaned_controllers.end(), server_controllers.begin(), server_controllers.end());
|
||||
|
||||
server_controllers.clear();
|
||||
|
||||
ControllerListMutex.unlock();
|
||||
|
||||
DeleteOrphanedControllers();
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
@@ -326,6 +340,36 @@ void NetworkClient::StopClient()
|
||||
SignalNetworkClientUpdate(NETWORKCLIENT_UPDATE_REASON_CLIENT_STOPPED);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Controller teardown functions |
|
||||
\*---------------------------------------------------------*/
|
||||
void NetworkClient::TakeOrphanedControllers(std::vector<RGBController*>& orphaned)
|
||||
{
|
||||
ControllerListMutex.lock();
|
||||
|
||||
orphaned.insert(orphaned.end(), orphaned_controllers.begin(), orphaned_controllers.end());
|
||||
|
||||
orphaned_controllers.clear();
|
||||
|
||||
ControllerListMutex.unlock();
|
||||
}
|
||||
|
||||
void NetworkClient::DeleteOrphanedControllers()
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Delete outside the mutex; the controller destructor |
|
||||
| waits for callbacks that are already running |
|
||||
\*-----------------------------------------------------*/
|
||||
std::vector<RGBController*> orphaned;
|
||||
|
||||
TakeOrphanedControllers(orphaned);
|
||||
|
||||
for(std::size_t orphaned_idx = 0; orphaned_idx < orphaned.size(); orphaned_idx++)
|
||||
{
|
||||
delete orphaned[orphaned_idx];
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkClient::SendRequest_ControllerData(unsigned int dev_id)
|
||||
{
|
||||
NetPacketHeader request_hdr;
|
||||
@@ -1905,23 +1949,27 @@ listen_done:
|
||||
server_initialized = false;
|
||||
server_connected = false;
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Do not delete the controllers here; the front end |
|
||||
| still holds pointers to them. Move them to |
|
||||
| orphaned_controllers for the teardown thread to free |
|
||||
\*-----------------------------------------------------*/
|
||||
ControllerListMutex.lock();
|
||||
|
||||
std::vector<RGBController *> server_controllers_copy = server_controllers;
|
||||
orphaned_controllers.insert(orphaned_controllers.end(), server_controllers.begin(), server_controllers.end());
|
||||
|
||||
server_controllers.clear();
|
||||
|
||||
for(size_t server_controller_idx = 0; server_controller_idx < server_controllers_copy.size(); server_controller_idx++)
|
||||
{
|
||||
delete server_controllers_copy[server_controller_idx];
|
||||
}
|
||||
|
||||
ControllerListMutex.unlock();
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Client info has changed, call the callbacks |
|
||||
| Signal only an unplanned connection loss; on a |
|
||||
| requested stop the caller runs the teardown |
|
||||
\*-----------------------------------------------------*/
|
||||
SignalNetworkClientUpdate(NETWORKCLIENT_UPDATE_REASON_CLIENT_DISCONNECTED);
|
||||
if(client_active)
|
||||
{
|
||||
SignalNetworkClientUpdate(NETWORKCLIENT_UPDATE_REASON_CLIENT_DISCONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
|
||||
Reference in new issue
Block a user