From 0e33c919dd5c954e0e9d266924c1650237bb95a1 Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Sun, 26 Feb 2012 00:36:51 +0000 Subject: Using cSocketThreads for client outgoing packets. Unfortunately had to put in one intermediate thread (cServer::cNotifyWriteThread) to avoid deadlocks. Still, seems we have a proper multithreading for clients and no more per-client threads, yay :) git-svn-id: http://mc-server.googlecode.com/svn/trunk@328 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/cServer.cpp | 160 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 136 insertions(+), 24 deletions(-) (limited to 'source/cServer.cpp') diff --git a/source/cServer.cpp b/source/cServer.cpp index 97bcffaae..b1dab21e5 100644 --- a/source/cServer.cpp +++ b/source/cServer.cpp @@ -65,8 +65,6 @@ struct cServer::sServerState cThread* pListenThread; bool bStopListenThread; cThread* pTickThread; bool bStopTickThread; - ClientList Clients; - cEvent RestartEvent; std::string ServerID; }; @@ -109,6 +107,33 @@ void cServer::ClientDestroying(const cClientHandle * a_Client) +void cServer::NotifyClientWrite(const cClientHandle * a_Client) +{ + m_NotifyWriteThread.NotifyClientWrite(a_Client); +} + + + + + +void cServer::WriteToClient(const cSocket * a_Socket, const AString & a_Data) +{ + m_SocketThreads.Write(a_Socket, a_Data); +} + + + + + +void cServer::QueueClientClose(const cSocket * a_Socket) +{ + m_SocketThreads.QueueClose(a_Socket); +} + + + + + bool cServer::InitServer( int a_Port ) { if( m_bIsConnected ) @@ -209,6 +234,9 @@ bool cServer::InitServer( int a_Port ) LOGINFO("Setting default viewdistance to the maximum of %d", m_ClientViewDistance); } } + + m_NotifyWriteThread.Start(this); + return true; } @@ -250,9 +278,13 @@ cServer::~cServer() // TODO - Need to modify this or something, so it broadcasts to all worlds? And move this to cWorld? void cServer::Broadcast( const cPacket * a_Packet, cClientHandle* a_Exclude /* = 0 */ ) { - for( ClientList::iterator itr = m_pState->Clients.begin(); itr != m_pState->Clients.end(); ++itr) + cCSLock Lock(m_CSClients); + for( ClientList::iterator itr = m_Clients.begin(); itr != m_Clients.end(); ++itr) { - if( *itr == a_Exclude || !(*itr)->IsLoggedIn() ) continue; + if ((*itr == a_Exclude) || !(*itr)->IsLoggedIn()) + { + continue; + } (*itr)->Send( a_Packet ); } } @@ -289,7 +321,9 @@ void cServer::StartListenClient() delete NewHandle; return; } - m_pState->Clients.push_back( NewHandle ); // TODO - lock list + + cCSLock Lock(m_CSClients); + m_Clients.push_back( NewHandle ); } @@ -310,21 +344,21 @@ bool cServer::Tick(float a_Dt) cRoot::Get()->TickWorlds( a_Dt ); // TODO - Maybe give all worlds their own thread? - //World->LockClientHandle(); // TODO - Lock client list - for( ClientList::iterator itr = m_pState->Clients.begin(); itr != m_pState->Clients.end();) { - if( (*itr)->IsDestroyed() ) + cCSLock Lock(m_CSClients); + for (cClientHandleList::iterator itr = m_Clients.begin(); itr != m_Clients.end();) { - cClientHandle* RemoveMe = *itr; + if ((*itr)->IsDestroyed()) + { + cClientHandle* RemoveMe = *itr; + itr = m_Clients.erase(itr); + delete RemoveMe; + continue; + } + (*itr)->Tick(a_Dt); ++itr; - m_pState->Clients.remove( RemoveMe ); - delete RemoveMe; - continue; } - (*itr)->Tick(a_Dt); - ++itr; } - //World->UnlockClientHandle(); cRoot::Get()->GetPluginManager()->Tick( a_Dt ); @@ -550,14 +584,12 @@ void cServer::Shutdown() cRoot::Get()->GetWorld()->SaveAllChunks(); - //cWorld* World = cRoot::Get()->GetWorld(); - //World->LockClientHandle(); // TODO - Lock client list - for( ClientList::iterator itr = m_pState->Clients.begin(); itr != m_pState->Clients.end(); ++itr ) + cCSLock Lock(m_CSClients); + for( ClientList::iterator itr = m_Clients.begin(); itr != m_Clients.end(); ++itr ) { delete *itr; } - m_pState->Clients.clear(); - //World->UnlockClientHandle(); + m_Clients.clear(); } @@ -575,13 +607,14 @@ const AString & cServer::GetServerID(void) const void cServer::KickUser(const AString & iUserName, const AString & iReason) { - for (ClientList::iterator itr = m_pState->Clients.begin(); itr != m_pState->Clients.end(); ++itr) + cCSLock Lock(m_CSClients); + for (ClientList::iterator itr = m_Clients.begin(); itr != m_Clients.end(); ++itr) { if ((*itr)->GetUsername() == iUserName) { (*itr)->Kick(iReason); } - } // for itr - m_pState->Clients[] + } // for itr - m_Clients[] } @@ -590,13 +623,92 @@ void cServer::KickUser(const AString & iUserName, const AString & iReason) void cServer::AuthenticateUser(const AString & iUserName) { - for (ClientList::iterator itr = m_pState->Clients.begin(); itr != m_pState->Clients.end(); ++itr) + cCSLock Lock(m_CSClients); + for (ClientList::iterator itr = m_Clients.begin(); itr != m_Clients.end(); ++itr) { if ((*itr)->GetUsername() == iUserName) { (*itr)->Authenticate(); } - } // for itr - m_pState->Clients[] + } // for itr - m_Clients[] +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cServer::cClientPacketThread: + +cServer::cNotifyWriteThread::cNotifyWriteThread(void) : + super("ClientPacketThread"), + m_Server(NULL) +{ +} + + + + + +cServer::cNotifyWriteThread::~cNotifyWriteThread() +{ + mShouldTerminate = true; + m_Event.Set(); + Wait(); +} + + + + + +bool cServer::cNotifyWriteThread::Start(cServer * a_Server) +{ + m_Server = a_Server; + return super::Start(); +} + + + + + +void cServer::cNotifyWriteThread::Execute(void) +{ + cClientHandleList Clients; + while (!mShouldTerminate) + { + cCSLock Lock(m_CS); + while (m_Clients.size() == 0) + { + cCSUnlock Unlock(Lock); + m_Event.Wait(); + if (mShouldTerminate) + { + return; + } + } + + // Copy the clients to notify and unlock the CS: + Clients.splice(Clients.begin(), m_Clients); + Lock.Unlock(); + + for (cClientHandleList::iterator itr = Clients.begin(); itr != Clients.end(); ++itr) + { + m_Server->m_SocketThreads.NotifyWrite(*itr); + } // for itr - Clients[] + Clients.clear(); + } // while (!mShouldTerminate) +} + + + + + +void cServer::cNotifyWriteThread::NotifyClientWrite(const cClientHandle * a_Client) +{ + cCSLock Lock(m_CS); + m_Clients.remove(const_cast(a_Client)); // Put it there only once + m_Clients.push_back(const_cast(a_Client)); + m_Event.Set(); } -- cgit v1.2.3