Use atomic flag to start / stop listening thread
This commit is contained in:
parent
cfeadf335c
commit
372753f505
@ -43,8 +43,7 @@
|
||||
# include <errno.h>
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <functional>
|
||||
|
||||
STKHost *STKHost::m_stk_host = NULL;
|
||||
bool STKHost::m_enable_console = false;
|
||||
@ -303,12 +302,12 @@ void STKHost::init()
|
||||
m_shutdown = false;
|
||||
m_network = NULL;
|
||||
m_lan_network = NULL;
|
||||
m_listening_thread = NULL;
|
||||
m_game_setup = NULL;
|
||||
m_is_registered = false;
|
||||
m_error_message = "";
|
||||
|
||||
pthread_mutex_init(&m_exit_mutex, NULL);
|
||||
m_exit_flag.clear();
|
||||
m_exit_flag.test_and_set();
|
||||
|
||||
// Start with initialising ENet
|
||||
// ============================
|
||||
@ -355,18 +354,6 @@ STKHost::~STKHost()
|
||||
delete m_network;
|
||||
} // ~STKHost
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Requests that the network infrastructure is to be shut down. This function
|
||||
* is called from a thread, but the actual shutdown needs to be done from
|
||||
* the main thread to avoid race conditions (e.g. ProtocolManager might still
|
||||
* access data structures when the main thread tests if STKHost exist (which
|
||||
* it does, but ProtocolManager might be shut down already.
|
||||
*/
|
||||
void STKHost::requestShutdown()
|
||||
{
|
||||
m_shutdown = true;
|
||||
} // requestExit
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Called from the main thread when the network infrastructure is to be shut
|
||||
* down.
|
||||
@ -462,9 +449,9 @@ bool STKHost::connect(const TransportAddress& address)
|
||||
*/
|
||||
void STKHost::startListening()
|
||||
{
|
||||
pthread_mutex_lock(&m_exit_mutex); // will let the update function start
|
||||
m_listening_thread = new pthread_t;
|
||||
pthread_create(m_listening_thread, NULL, &STKHost::mainLoop, this);
|
||||
m_exit_flag.clear();
|
||||
m_exit_flag.test_and_set();
|
||||
m_listening_thread = std::thread(std::bind(&STKHost::mainLoop, this));
|
||||
} // startListening
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -473,29 +460,11 @@ void STKHost::startListening()
|
||||
*/
|
||||
void STKHost::stopListening()
|
||||
{
|
||||
if (m_listening_thread)
|
||||
{
|
||||
// This will stop the update function on its next update
|
||||
pthread_mutex_unlock(&m_exit_mutex);
|
||||
pthread_join(*m_listening_thread, NULL); // wait for the thread to end
|
||||
}
|
||||
m_exit_flag.clear();
|
||||
if (m_listening_thread.joinable())
|
||||
m_listening_thread.join();
|
||||
} // stopListening
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** \brief Returns true when the thread should stop listening.
|
||||
*/
|
||||
int STKHost::mustStopListening()
|
||||
{
|
||||
switch (pthread_mutex_trylock(&m_exit_mutex)) {
|
||||
case 0: /* if we got the lock, unlock and return 1 (true) */
|
||||
pthread_mutex_unlock(&m_exit_mutex);
|
||||
return 1;
|
||||
case EBUSY: /* return 0 (false) if the mutex was locked */
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
} // mustStopListening
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns true if this client instance is allowed to control the server.
|
||||
* A client can authorise itself by providing the server's password. It is
|
||||
@ -520,26 +489,25 @@ bool STKHost::isAuthorisedToControl() const
|
||||
* event and passes it to the Network Manager.
|
||||
* \param self : used to pass the ENet host to the function.
|
||||
*/
|
||||
void* STKHost::mainLoop(void* self)
|
||||
void STKHost::mainLoop()
|
||||
{
|
||||
VS::setThreadName("STKHost");
|
||||
ENetEvent event;
|
||||
STKHost* myself = (STKHost*)(self);
|
||||
ENetHost* host = myself->m_network->getENetHost();
|
||||
ENetHost* host = m_network->getENetHost();
|
||||
|
||||
if(NetworkConfig::get()->isServer() &&
|
||||
(NetworkConfig::get()->isLAN() || NetworkConfig::get()->isPublicServer()) )
|
||||
{
|
||||
TransportAddress address(0, NetworkConfig::get()->getServerDiscoveryPort());
|
||||
ENetAddress eaddr = address.toEnetAddress();
|
||||
myself->m_lan_network = new Network(1, 1, 0, 0, &eaddr);
|
||||
m_lan_network = new Network(1, 1, 0, 0, &eaddr);
|
||||
}
|
||||
|
||||
while (!myself->mustStopListening())
|
||||
while (m_exit_flag.test_and_set())
|
||||
{
|
||||
if(myself->m_lan_network)
|
||||
if(m_lan_network)
|
||||
{
|
||||
myself->handleDirectSocketRequest();
|
||||
handleDirectSocketRequest();
|
||||
} // if discovery host
|
||||
|
||||
while (enet_host_service(host, &event, 20) != 0)
|
||||
@ -561,7 +529,7 @@ void* STKHost::mainLoop(void* self)
|
||||
if (stk_event->getType() == EVENT_TYPE_CONNECTED)
|
||||
{
|
||||
Log::info("STKHost", "A client has just connected. There are "
|
||||
"now %lu peers.", myself->m_peers.size());
|
||||
"now %lu peers.", m_peers.size());
|
||||
Log::debug("STKHost", "Addresses are : %lx, %lx",
|
||||
stk_event->getPeer(), peer);
|
||||
} // EVENT_TYPE_CONNECTED
|
||||
@ -588,12 +556,8 @@ void* STKHost::mainLoop(void* self)
|
||||
pm->propagateEvent(stk_event);
|
||||
|
||||
} // while enet_host_service
|
||||
} // while !mustStopListening
|
||||
|
||||
free(myself->m_listening_thread);
|
||||
myself->m_listening_thread = NULL;
|
||||
} // while m_exit_flag.test_and_set()
|
||||
Log::info("STKHost", "Listening has been stopped");
|
||||
return NULL;
|
||||
} // mainLoop
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -38,7 +38,8 @@
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <enet/enet.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
class GameSetup;
|
||||
class NetworkConsole;
|
||||
@ -88,14 +89,14 @@ private:
|
||||
GameSetup* m_game_setup;
|
||||
|
||||
/** Id of thread listening to enet events. */
|
||||
pthread_t* m_listening_thread;
|
||||
std::thread m_listening_thread;
|
||||
|
||||
/** Flag which is set from the protocol manager thread which
|
||||
* triggers a shutdown of the STKHost (and the Protocolmanager). */
|
||||
bool m_shutdown;
|
||||
std::atomic_bool m_shutdown;
|
||||
|
||||
/** Mutex used to stop this thread. */
|
||||
pthread_mutex_t m_exit_mutex;
|
||||
/** Atomic flag used to stop this thread. */
|
||||
std::atomic_flag m_exit_flag = ATOMIC_FLAG_INIT;
|
||||
|
||||
/** If this is a server, it indicates if this server is registered
|
||||
* with the stk server. */
|
||||
@ -111,6 +112,9 @@ private:
|
||||
void init();
|
||||
void handleDirectSocketRequest();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
void mainLoop();
|
||||
|
||||
public:
|
||||
/** If a network console should be started. Note that the console can cause
|
||||
* a crash in release mode on windows (see #1529). */
|
||||
@ -139,15 +143,25 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Checks if the STKHost has been created. */
|
||||
static bool existHost() { return m_stk_host != NULL; }
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
static void* mainLoop(void* self);
|
||||
|
||||
virtual GameSetup* setupNewGame();
|
||||
void abort();
|
||||
void deleteAllPeers();
|
||||
bool connect(const TransportAddress& peer);
|
||||
void requestShutdown();
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/** Requests that the network infrastructure is to be shut down. This
|
||||
* function is called from a thread, but the actual shutdown needs to be
|
||||
* done from the main thread to avoid race conditions (e.g.
|
||||
* ProtocolManager might still access data structures when the main thread
|
||||
* tests if STKHost exist (which it does, but ProtocolManager might be
|
||||
* shut down already.
|
||||
*/
|
||||
void requestShutdown()
|
||||
{
|
||||
m_shutdown.store(true);
|
||||
} // requestExit
|
||||
//-------------------------------------------------------------------------
|
||||
void shutdown();
|
||||
|
||||
void sendPacketExcept(STKPeer* peer,
|
||||
@ -164,7 +178,6 @@ public:
|
||||
STKPeer *getPeer(ENetPeer *enet_peer);
|
||||
STKPeer *getServerPeerForClient() const;
|
||||
std::vector<NetworkPlayerProfile*> getMyPlayerProfiles();
|
||||
int mustStopListening();
|
||||
uint16_t getPort() const;
|
||||
void setErrorMessage(const irr::core::stringw &message);
|
||||
bool isAuthorisedToControl() const;
|
||||
@ -174,7 +187,7 @@ public:
|
||||
// --------------------------------------------------------------------
|
||||
/** Returns true if a shutdown of the network infrastructure was
|
||||
* requested. */
|
||||
bool requestedShutdown() const { return m_shutdown; }
|
||||
bool requestedShutdown() const { return m_shutdown.load(); }
|
||||
// --------------------------------------------------------------------
|
||||
/** Returns the current game setup. */
|
||||
GameSetup* getGameSetup() { return m_game_setup; }
|
||||
|
Loading…
x
Reference in New Issue
Block a user