1
0

Added network termination called at app exit.

This fixes a crash in MSVC runtime caused by joining a thread in a global var's destructor.
This commit is contained in:
Mattes D 2015-01-26 14:46:20 +01:00
parent 9a2200f8bb
commit 053362e604
6 changed files with 91 additions and 18 deletions

View File

@ -18,7 +18,8 @@
cNetworkSingleton::cNetworkSingleton(void)
cNetworkSingleton::cNetworkSingleton(void):
m_HasTerminated(false)
{
// Windows: initialize networking:
#ifdef _WIN32
@ -72,6 +73,29 @@ cNetworkSingleton::cNetworkSingleton(void)
cNetworkSingleton::~cNetworkSingleton()
{
// Check that Terminate has been called already:
ASSERT(m_HasTerminated);
}
cNetworkSingleton & cNetworkSingleton::Get(void)
{
static cNetworkSingleton Instance;
return Instance;
}
void cNetworkSingleton::Terminate(void)
{
ASSERT(!m_HasTerminated);
m_HasTerminated = true;
// Wait for the LibEvent event loop to terminate:
event_base_loopbreak(m_EventBase);
m_EventLoopTerminated.Wait();
@ -96,16 +120,6 @@ cNetworkSingleton::~cNetworkSingleton()
cNetworkSingleton & cNetworkSingleton::Get(void)
{
static cNetworkSingleton Instance;
return Instance;
}
void cNetworkSingleton::LogCallback(int a_Severity, const char * a_Msg)
{
switch (a_Severity)
@ -138,6 +152,7 @@ void cNetworkSingleton::RunEventLoop(cNetworkSingleton * a_Self)
void cNetworkSingleton::AddHostnameLookup(cHostnameLookupPtr a_HostnameLookup)
{
ASSERT(!m_HasTerminated);
cCSLock Lock(m_CS);
m_HostnameLookups.push_back(a_HostnameLookup);
}
@ -148,6 +163,7 @@ void cNetworkSingleton::AddHostnameLookup(cHostnameLookupPtr a_HostnameLookup)
void cNetworkSingleton::RemoveHostnameLookup(const cHostnameLookup * a_HostnameLookup)
{
ASSERT(!m_HasTerminated);
cCSLock Lock(m_CS);
for (auto itr = m_HostnameLookups.begin(), end = m_HostnameLookups.end(); itr != end; ++itr)
{
@ -165,6 +181,7 @@ void cNetworkSingleton::RemoveHostnameLookup(const cHostnameLookup * a_HostnameL
void cNetworkSingleton::AddIPLookup(cIPLookupPtr a_IPLookup)
{
ASSERT(!m_HasTerminated);
cCSLock Lock(m_CS);
m_IPLookups.push_back(a_IPLookup);
}
@ -175,6 +192,7 @@ void cNetworkSingleton::AddIPLookup(cIPLookupPtr a_IPLookup)
void cNetworkSingleton::RemoveIPLookup(const cIPLookup * a_IPLookup)
{
ASSERT(!m_HasTerminated);
cCSLock Lock(m_CS);
for (auto itr = m_IPLookups.begin(), end = m_IPLookups.end(); itr != end; ++itr)
{
@ -192,6 +210,7 @@ void cNetworkSingleton::RemoveIPLookup(const cIPLookup * a_IPLookup)
void cNetworkSingleton::AddLink(cTCPLinkImplPtr a_Link)
{
ASSERT(!m_HasTerminated);
cCSLock Lock(m_CS);
m_Connections.push_back(a_Link);
}
@ -202,6 +221,7 @@ void cNetworkSingleton::AddLink(cTCPLinkImplPtr a_Link)
void cNetworkSingleton::RemoveLink(const cTCPLinkImpl * a_Link)
{
ASSERT(!m_HasTerminated);
cCSLock Lock(m_CS);
for (auto itr = m_Connections.begin(), end = m_Connections.end(); itr != end; ++itr)
{
@ -219,6 +239,7 @@ void cNetworkSingleton::RemoveLink(const cTCPLinkImpl * a_Link)
void cNetworkSingleton::AddServer(cServerHandleImplPtr a_Server)
{
ASSERT(!m_HasTerminated);
cCSLock Lock(m_CS);
m_Servers.push_back(a_Server);
}
@ -229,6 +250,7 @@ void cNetworkSingleton::AddServer(cServerHandleImplPtr a_Server)
void cNetworkSingleton::RemoveServer(const cServerHandleImpl * a_Server)
{
ASSERT(!m_HasTerminated);
cCSLock Lock(m_CS);
for (auto itr = m_Servers.begin(), end = m_Servers.end(); itr != end; ++itr)
{

View File

@ -4,7 +4,8 @@
// Declares the cNetworkSingleton class representing the storage for global data pertaining to network API
// such as a list of all connections, all listening sockets and the LibEvent dispatch thread.
// This is an internal header, no-one outside OSSupport should need to include it; use Network.h instead
// This is an internal header, no-one outside OSSupport should need to include it; use Network.h instead;
// the only exception being the main app entrypoint that needs to call Terminate before quitting.
@ -48,6 +49,11 @@ public:
/** Returns the singleton instance of this class */
static cNetworkSingleton & Get(void);
/** Terminates all network-related threads.
To be used only on app shutdown.
MSVC runtime requires that the LibEvent networking be shut down before the main() function is exitted; this is the way to do it. */
void Terminate(void);
/** Returns the main LibEvent handle for event registering. */
event_base * GetEventBase(void) { return m_EventBase; }
@ -113,6 +119,9 @@ protected:
/** Event that gets signalled when the event loop terminates. */
cEvent m_EventLoopTerminated;
/** Set to true if Terminate has been called. */
volatile bool m_HasTerminated;
/** Initializes the LibEvent internals. */
cNetworkSingleton(void);

View File

@ -11,14 +11,18 @@
#include <dbghelp.h>
#endif // _MSC_VER
bool cRoot::m_TerminateEventRaised = false; // If something has told the server to stop; checked periodically in cRoot
static bool g_ServerTerminated = false; // Set to true when the server terminates, so our CTRL handler can then tell the OS to close the console
#include "OSSupport/NetworkSingleton.h"
/** If something has told the server to stop; checked periodically in cRoot */
bool cRoot::m_TerminateEventRaised = false;
/** Set to true when the server terminates, so our CTRL handler can then tell the OS to close the console. */
static bool g_ServerTerminated = false;
/** If set to true, the protocols will log each player's incoming (C->S) communication to a per-connection logfile */
bool g_ShouldLogCommIn;
@ -305,6 +309,9 @@ int main( int argc, char **argv)
g_ServerTerminated = true;
// Shutdown all of LibEvent:
cNetworkSingleton::Get().Terminate();
return EXIT_SUCCESS;
}

View File

@ -7,6 +7,7 @@
#include <iostream>
#include <string>
#include "OSSupport/Network.h"
#include "OSSupport/NetworkSingleton.h"
@ -98,7 +99,7 @@ class cEchoServerCallbacks:
int main()
void DoTest(void)
{
LOGD("EchoServer: starting up");
cServerHandlePtr Server = cNetwork::Listen(9876, std::make_shared<cEchoServerCallbacks>());
@ -119,9 +120,20 @@ int main()
Server->Close();
ASSERT(!Server->IsListening());
LOGD("Server has been closed.");
}
int main()
{
DoTest();
printf("Press enter to exit test.\n");
AString line;
std::getline(std::cin, line);
cNetworkSingleton::Get().Terminate();
LOG("Network test finished.");
return 0;

View File

@ -7,6 +7,7 @@
#include <thread>
#include "OSSupport/Event.h"
#include "OSSupport/Network.h"
#include "OSSupport/NetworkSingleton.h"
@ -96,7 +97,7 @@ public:
int main()
void DoTest(void)
{
cEvent evtFinish;
@ -109,7 +110,19 @@ int main()
LOGD("Connect request has been queued.");
evtFinish.Wait();
}
int main()
{
DoTest();
cNetworkSingleton::Get().Terminate();
LOGD("Network test finished");
return 0;
}

View File

@ -7,6 +7,7 @@
#include <thread>
#include "OSSupport/Event.h"
#include "OSSupport/Network.h"
#include "OSSupport/NetworkSingleton.h"
@ -45,7 +46,7 @@ public:
int main()
void DoTest(void)
{
cEvent evtFinish;
@ -70,7 +71,16 @@ int main()
LOGD("IP lookup has been successfully queued");
evtFinish.Wait();
LOGD("IP lookup finished.");
}
int main()
{
DoTest();
cNetworkSingleton::Get().Terminate();
LOGD("Network test finished");
return 0;
}