diff --git a/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp b/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp index d4ef5b3ba8..94ae4cbfbf 100644 --- a/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp +++ b/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp @@ -93,40 +93,63 @@ bool RCON_IsRemoteAllowedToConnect(const AZ::AzSock::AzSocketAddress& connectee) ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// +void SRemoteThreadedObject::Start(const char* name) +{ + AZStd::thread_desc desc; + desc.m_name = name; + auto function = AZStd::bind(&SRemoteThreadedObject::ThreadFunction, this); + m_thread = AZStd::thread(function, &desc); +} + +void SRemoteThreadedObject::WaitForThread() +{ + if (m_thread.joinable()) + { + m_thread.join(); + } +} + +void SRemoteThreadedObject::ThreadFunction() +{ + Run(); + Terminate(); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// void SRemoteServer::StartServer() { StopServer(); m_bAcceptClients = true; - Start(0, kServerThreadName); + Start(kServerThreadName); } ///////////////////////////////////////////////////////////////////////////////////////////// void SRemoteServer::StopServer() { - Stop(); m_bAcceptClients = false; AZ::AzSock::CloseSocket(m_socket); m_socket = SOCKET_ERROR; - m_lock.Lock(); - for (TClients::iterator it = m_clients.begin(); it != m_clients.end(); ++it) { - it->pClient->StopClient(); + AZStd::lock_guard lock(m_mutex); + for (TClients::iterator it = m_clients.begin(); it != m_clients.end(); ++it) + { + it->pClient->StopClient(); + } } - m_lock.Unlock(); - m_stopEvent.Wait(); - m_stopEvent.Set(); -} + AZStd::unique_lock lock(m_mutex); + m_stopCondition.wait(lock, [this] { return m_clients.empty(); });} ///////////////////////////////////////////////////////////////////////////////////////////// void SRemoteServer::ClientDone(SRemoteClient* pClient) { - m_lock.Lock(); + AZStd::lock_guard lock(m_mutex); for (TClients::iterator it = m_clients.begin(); it != m_clients.end(); ++it) { if (it->pClient == pClient) { - it->pClient->Stop(); delete it->pClient; delete it->pEvents; m_clients.erase(it); @@ -136,9 +159,8 @@ void SRemoteServer::ClientDone(SRemoteClient* pClient) if (m_clients.empty()) { - m_stopEvent.Set(); + m_stopCondition.notify_all(); } - m_lock.Unlock(); } ///////////////////////////////////////////////////////////////////////////////////////////// @@ -149,7 +171,6 @@ void SRemoteServer::Terminate() ///////////////////////////////////////////////////////////////////////////////////////////// void SRemoteServer::Run() { - SetName(kServerThreadName); AZ_TRAIT_REMOTECONSOLE_SET_THREAD_AFFINITY AZSOCKET sClient; @@ -232,12 +253,10 @@ void SRemoteServer::Run() continue; } - m_lock.Lock(); - m_stopEvent.Reset(); + AZStd::lock_guard lock(m_mutex); SRemoteClient* pClient = new SRemoteClient(this); m_clients.push_back(SRemoteClientInfo(pClient)); pClient->StartClient(sClient); - m_lock.Unlock(); } AZ::AzSock::CloseSocket(m_socket); CryLog("Remote console terminating.\n"); @@ -247,43 +266,42 @@ void SRemoteServer::Run() ///////////////////////////////////////////////////////////////////////////////////////////// void SRemoteServer::AddEvent(IRemoteEvent* pEvent) { - m_lock.Lock(); + AZStd::lock_guard lock(m_mutex); for (TClients::iterator it = m_clients.begin(); it != m_clients.end(); ++it) { it->pEvents->push_back(pEvent->Clone()); } - m_lock.Unlock(); delete pEvent; } ///////////////////////////////////////////////////////////////////////////////////////////// void SRemoteServer::GetEvents(TEventBuffer& buffer) { - m_lock.Lock(); + AZStd::lock_guard lock(m_mutex); buffer = m_eventBuffer; m_eventBuffer.clear(); - m_lock.Unlock(); } ///////////////////////////////////////////////////////////////////////////////////////////// bool SRemoteServer::WriteBuffer(SRemoteClient* pClient, char* buffer, int& size) { - m_lock.Lock(); IRemoteEvent* pEvent = nullptr; - for (TClients::iterator it = m_clients.begin(); it != m_clients.end(); ++it) { - if (it->pClient == pClient) + AZStd::lock_guard lock(m_mutex); + for (TClients::iterator it = m_clients.begin(); it != m_clients.end(); ++it) { - TEventBuffer* pEvents = it->pEvents; - if (!pEvents->empty()) + if (it->pClient == pClient) { - pEvent = pEvents->front(); - pEvents->pop_front(); + TEventBuffer* pEvents = it->pEvents; + if (!pEvents->empty()) + { + pEvent = pEvents->front(); + pEvents->pop_front(); + } + break; } - break; } } - m_lock.Unlock(); const bool res = (pEvent != nullptr); if (pEvent) { @@ -297,7 +315,7 @@ bool SRemoteServer::WriteBuffer(SRemoteClient* pClient, char* buffer, int& size bool SRemoteServer::ReadBuffer(const char* buffer, int data) { bool result = true; - + // Sometimes multiple events can come in a single buffer, so make sure we look // at the entire thing. int bytesRemaining = data; @@ -306,15 +324,14 @@ bool SRemoteServer::ReadBuffer(const char* buffer, int data) { // Create the event from the current sub string in the buffer. IRemoteEvent* event = SRemoteEventFactory::GetInst()->CreateEventFromBuffer(curBuffer, bytesRemaining); - + result &= (event != nullptr); if (event) { if (event->GetType() != eCET_Noop) { - m_lock.Lock(); + AZStd::lock_guard lock(m_mutex); m_eventBuffer.push_back(event); - m_lock.Unlock(); } else { @@ -337,7 +354,7 @@ bool SRemoteServer::ReadBuffer(const char* buffer, int data) void SRemoteClient::StartClient(AZSOCKET socket) { m_socket = socket; - Start(0, kClientThreadName); + Start(kClientThreadName); } ///////////////////////////////////////////////////////////////////////////////////////////// @@ -356,7 +373,6 @@ void SRemoteClient::Terminate() ///////////////////////////////////////////////////////////////////////////////////////////// void SRemoteClient::Run() { - SetName(kClientThreadName); AZ_TRAIT_REMOTECONSOLE_SET_THREAD_AFFINITY char szBuff[kDefaultBufferSize]; diff --git a/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.h b/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.h index 45c3bf62d9..7e22be5735 100644 --- a/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.h +++ b/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.h @@ -11,9 +11,11 @@ #include #include #include +#include +#include +#include #include -#include extern const int defaultRemoteConsolePort; @@ -146,6 +148,30 @@ private: typedef AZStd::list TEventBuffer; + +///////////////////////////////////////////////////////////////////////////////////////////// +// SRemoteThreadedObject +// +// Simple runnable-like threaded object +// +///////////////////////////////////////////////////////////////////////////////////////////// +struct SRemoteThreadedObject +{ + virtual ~SRemoteThreadedObject() = default; + + void Start(const char* name); + + void WaitForThread(); + + virtual void Run() = 0; + virtual void Terminate() = 0; + +private: + void ThreadFunction(); + + AZStd::thread m_thread; +}; + ///////////////////////////////////////////////////////////////////////////////////////////// // SRemoteServer // @@ -154,10 +180,10 @@ typedef AZStd::list TEventBuffer; ///////////////////////////////////////////////////////////////////////////////////////////// struct SRemoteClient; struct SRemoteServer - : public CrySimpleThread<> + : public SRemoteThreadedObject { SRemoteServer() - : m_socket(AZ_SOCKET_INVALID) { m_stopEvent.Set(); } + : m_socket(AZ_SOCKET_INVALID) {} void StartServer(); void StopServer(); @@ -165,10 +191,8 @@ struct SRemoteServer void AddEvent(IRemoteEvent* pEvent); void GetEvents(TEventBuffer& buffer); - // CrySimpleThread void Terminate() override; void Run() override; - // ~CrySimpleThread private: bool WriteBuffer(SRemoteClient* pClient, char* buffer, int& size); @@ -189,9 +213,9 @@ private: typedef AZStd::vector TClients; TClients m_clients; AZSOCKET m_socket; - CryMutex m_lock; + AZStd::recursive_mutex m_mutex; TEventBuffer m_eventBuffer; - CryEvent m_stopEvent; + AZStd::condition_variable_any m_stopCondition; volatile bool m_bAcceptClients; friend struct SRemoteClient; }; @@ -204,7 +228,7 @@ private: // ///////////////////////////////////////////////////////////////////////////////////////////// struct SRemoteClient - : public CrySimpleThread<> + : public SRemoteThreadedObject { SRemoteClient(SRemoteServer* pServer) : m_pServer(pServer) @@ -213,10 +237,8 @@ struct SRemoteClient void StartClient(AZSOCKET socket); void StopClient(); - // CrySimpleThread void Terminate() override; void Run() override; - // ~CrySimpleThread private: bool RecvPackage(char* buffer, int& size);