[General] Fix a few memory leaks in threads

Destroying threads past when uninitializing the library is illegal
This commit is contained in:
momo5502 2017-01-23 22:06:50 +01:00
parent 54323c2c0b
commit 80e88f1572
13 changed files with 63 additions and 4 deletions

View File

@ -3,6 +3,7 @@
namespace Components namespace Components
{ {
bool Loader::Pregame = true; bool Loader::Pregame = true;
bool Loader::Postgame = false;
std::vector<Component*> Loader::Components; std::vector<Component*> Loader::Components;
Utils::Memory::Allocator Loader::MemAllocator; Utils::Memory::Allocator Loader::MemAllocator;
@ -14,6 +15,7 @@ namespace Components
void Loader::Initialize() void Loader::Initialize()
{ {
Loader::Pregame = true; Loader::Pregame = true;
Loader::Postgame = false;
Loader::MemAllocator.clear(); Loader::MemAllocator.clear();
Loader::Register(new Flags()); Loader::Register(new Flags());
@ -86,6 +88,8 @@ namespace Components
void Loader::Uninitialize() void Loader::Uninitialize()
{ {
Loader::PreDestroy();
std::reverse(Loader::Components.begin(), Loader::Components.end()); std::reverse(Loader::Components.begin(), Loader::Components.end());
for (auto component : Loader::Components) for (auto component : Loader::Components)
{ {
@ -102,6 +106,20 @@ namespace Components
Loader::MemAllocator.clear(); Loader::MemAllocator.clear();
} }
void Loader::PreDestroy()
{
if(!Loader::Postgame)
{
Loader::Postgame = true;
std::reverse(Loader::Components.begin(), Loader::Components.end());
for (auto component : Loader::Components)
{
component->preDestroy();
}
}
}
bool Loader::PerformUnitTests() bool Loader::PerformUnitTests()
{ {
bool result = true; bool result = true;

View File

@ -12,6 +12,10 @@ namespace Components
virtual const char* getName() { return "Unknown"; }; virtual const char* getName() { return "Unknown"; };
#endif #endif
// It's illegal to spawn threads in DLLMain, and apparently it causes problems if they are destroyed there as well.
// This method is called before DLLMain (if possible) and should to destroy threads.
// It's not 100% guaranteed that it's called outside DLLMain, as it depends on the game, but it's 100% guaranteed, that it is called at all.
virtual void preDestroy() {};
virtual bool unitTest() { return true; }; // Unit testing entry virtual bool unitTest() { return true; }; // Unit testing entry
}; };
@ -20,6 +24,7 @@ namespace Components
public: public:
static void Initialize(); static void Initialize();
static void Uninitialize(); static void Uninitialize();
static void PreDestroy();
static bool PerformUnitTests(); static bool PerformUnitTests();
static bool PerformingUnitTests(); static bool PerformingUnitTests();
static void Register(Component* component); static void Register(Component* component);
@ -30,6 +35,7 @@ namespace Components
private: private:
static bool Pregame; static bool Pregame;
static bool Postgame;
static std::vector<Component*> Components; static std::vector<Component*> Components;
static Utils::Memory::Allocator MemAllocator; static Utils::Memory::Allocator MemAllocator;
}; };

View File

@ -438,6 +438,11 @@ namespace Components
} }
Auth::~Auth() Auth::~Auth()
{
Auth::StoreKey();
}
void Auth::preDestroy()
{ {
Auth::TokenContainer.cancel = true; Auth::TokenContainer.cancel = true;
Auth::TokenContainer.generating = false; Auth::TokenContainer.generating = false;
@ -447,8 +452,6 @@ namespace Components
{ {
Auth::TokenContainer.thread.join(); Auth::TokenContainer.thread.join();
} }
Auth::StoreKey();
} }
bool Auth::unitTest() bool Auth::unitTest()

View File

@ -12,6 +12,7 @@ namespace Components
const char* getName() override { return "Auth"; }; const char* getName() override { return "Auth"; };
#endif #endif
void preDestroy() override;
bool unitTest() override; bool unitTest() override;
static void StoreKey(); static void StoreKey();

View File

@ -98,6 +98,11 @@ namespace Components
} }
Discovery::~Discovery() Discovery::~Discovery()
{
}
void Discovery::preDestroy()
{ {
Discovery::IsPerforming = false; Discovery::IsPerforming = false;
Discovery::IsTerminating = true; Discovery::IsTerminating = true;

View File

@ -12,6 +12,8 @@ namespace Components
const char* getName() override { return "Discovery"; }; const char* getName() override { return "Discovery"; };
#endif #endif
void preDestroy() override;
static void Perform(); static void Perform();
private: private:

View File

@ -633,7 +633,11 @@ namespace Components
{ {
mg_mgr_free(&Download::Mgr); mg_mgr_free(&Download::Mgr);
} }
else }
void Download::preDestroy()
{
if (!Dedicated::IsEnabled())
{ {
Download::CLDownload.clear(); Download::CLDownload.clear();
} }

View File

@ -12,6 +12,8 @@ namespace Components
const char* getName() override { return "Download"; }; const char* getName() override { return "Download"; };
#endif #endif
void preDestroy() override;
static void InitiateClientDownload(std::string mod); static void InitiateClientDownload(std::string mod);
private: private:

View File

@ -234,4 +234,10 @@ namespace Components
IPCPipe::Write("ping", ""); IPCPipe::Write("ping", "");
}); });
} }
void IPCPipe::preDestroy()
{
//IPCPipe::ServerPipe.destroy();
//IPCPipe::ClientPipe.destroy();
}
} }

View File

@ -38,6 +38,8 @@ namespace Components
void setCallback(std::string command, Utils::Slot<PacketCallback> callback); void setCallback(std::string command, Utils::Slot<PacketCallback> callback);
void onConnect(Callback callback); void onConnect(Callback callback);
void destroy();
private: private:
Utils::Slot<void()> connectCallback; Utils::Slot<void()> connectCallback;
std::map<std::string, Utils::Slot<PacketCallback>> packetCallbacks; std::map<std::string, Utils::Slot<PacketCallback>> packetCallbacks;
@ -53,7 +55,6 @@ namespace Components
char pipeFile[MAX_PATH]; char pipeFile[MAX_PATH];
unsigned int reconnectAttempt; unsigned int reconnectAttempt;
void destroy();
void setName(std::string name); void setName(std::string name);
static void ReceiveThread(Pipe* pipe); static void ReceiveThread(Pipe* pipe);
@ -68,6 +69,8 @@ namespace Components
const char* getName() override { return "IPCPipe"; }; const char* getName() override { return "IPCPipe"; };
#endif #endif
void preDestroy() override;
static bool Write(std::string command, std::string data); static bool Write(std::string command, std::string data);
static void On(std::string command, Utils::Slot<Pipe::PacketCallback> callback); static void On(std::string command, Utils::Slot<Pipe::PacketCallback> callback);

View File

@ -190,6 +190,11 @@ namespace Components
} }
News::~News() News::~News()
{
}
void News::preDestroy()
{ {
News::Terminate = true; News::Terminate = true;

View File

@ -12,6 +12,7 @@ namespace Components
const char* getName() override { return "News"; }; const char* getName() override { return "News"; };
#endif #endif
void preDestroy() override;
bool unitTest() override; bool unitTest() override;
private: private:

View File

@ -174,6 +174,9 @@ namespace Components
QuickPatch::QuickPatch() QuickPatch::QuickPatch()
{ {
// Make sure preDestroy is called when the game shuts down
QuickPatch::OnShutdown(Loader::PreDestroy);
// protocol version (workaround for hacks) // protocol version (workaround for hacks)
Utils::Hook::Set<int>(0x4FB501, PROTOCOL); Utils::Hook::Set<int>(0x4FB501, PROTOCOL);