ChunkSender: Fixed a potential crash: removing a client means that no Send() is called on that client anymore
git-svn-id: http://mc-server.googlecode.com/svn/trunk@384 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
parent
0cee2428c1
commit
4544d5d3b9
@ -31,7 +31,7 @@ cChunkSender::cChunkSender(void) :
|
|||||||
cChunkSender::~cChunkSender()
|
cChunkSender::~cChunkSender()
|
||||||
{
|
{
|
||||||
mShouldTerminate = true;
|
mShouldTerminate = true;
|
||||||
m_Event.Set();
|
m_evtQueue.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ void cChunkSender::ChunkReady(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
|||||||
cCSLock Lock(m_CS);
|
cCSLock Lock(m_CS);
|
||||||
m_ChunksReady.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ));
|
m_ChunksReady.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ));
|
||||||
}
|
}
|
||||||
m_Event.Set();
|
m_evtQueue.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ void cChunkSender::QueueSendChunkTo(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cC
|
|||||||
cCSLock Lock(m_CS);
|
cCSLock Lock(m_CS);
|
||||||
m_SendChunks.push_back(sSendChunk(a_ChunkX, a_ChunkY, a_ChunkZ, a_Client));
|
m_SendChunks.push_back(sSendChunk(a_ChunkX, a_ChunkY, a_ChunkZ, a_Client));
|
||||||
}
|
}
|
||||||
m_Event.Set();
|
m_evtQueue.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -78,16 +78,20 @@ void cChunkSender::QueueSendChunkTo(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cC
|
|||||||
|
|
||||||
void cChunkSender::RemoveClient(cClientHandle * a_Client)
|
void cChunkSender::RemoveClient(cClientHandle * a_Client)
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CS);
|
|
||||||
for (sSendChunkList::iterator itr = m_SendChunks.begin(); itr != m_SendChunks.end();)
|
|
||||||
{
|
{
|
||||||
if (itr->m_Client == a_Client)
|
cCSLock Lock(m_CS);
|
||||||
|
for (sSendChunkList::iterator itr = m_SendChunks.begin(); itr != m_SendChunks.end();)
|
||||||
{
|
{
|
||||||
itr = m_SendChunks.erase(itr);
|
if (itr->m_Client == a_Client)
|
||||||
continue;
|
{
|
||||||
}
|
itr = m_SendChunks.erase(itr);
|
||||||
++itr;
|
continue;
|
||||||
} // for itr - m_SendChunks[]
|
}
|
||||||
|
++itr;
|
||||||
|
} // for itr - m_SendChunks[]
|
||||||
|
}
|
||||||
|
m_evtQueue.Set();
|
||||||
|
m_evtRemoved.Wait(); // Wait for removal confirmation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -102,7 +106,8 @@ void cChunkSender::Execute(void)
|
|||||||
while (m_ChunksReady.empty() && m_SendChunks.empty())
|
while (m_ChunksReady.empty() && m_SendChunks.empty())
|
||||||
{
|
{
|
||||||
cCSUnlock Unlock(Lock);
|
cCSUnlock Unlock(Lock);
|
||||||
m_Event.Wait();
|
m_evtRemoved.Set(); // Notify that the removed clients are safe to be deleted
|
||||||
|
m_evtQueue.Wait();
|
||||||
if (mShouldTerminate)
|
if (mShouldTerminate)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -127,6 +132,7 @@ void cChunkSender::Execute(void)
|
|||||||
|
|
||||||
SendChunk(Chunk.m_ChunkX, Chunk.m_ChunkY, Chunk.m_ChunkZ, Chunk.m_Client);
|
SendChunk(Chunk.m_ChunkX, Chunk.m_ChunkY, Chunk.m_ChunkZ, Chunk.m_Client);
|
||||||
}
|
}
|
||||||
|
m_evtRemoved.Set(); // Notify that the removed clients are safe to be deleted
|
||||||
} // while (!mShouldTerminate)
|
} // while (!mShouldTerminate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,10 @@ Chunk data is queried using the cChunkDataCallback interface.
|
|||||||
It is cached inside the ChunkSender object during the query and then processed after the query ends.
|
It is cached inside the ChunkSender object during the query and then processed after the query ends.
|
||||||
Note that the data needs to be compressed only *after* the query finishes,
|
Note that the data needs to be compressed only *after* the query finishes,
|
||||||
because the query callbacks run with ChunkMap's CS locked.
|
because the query callbacks run with ChunkMap's CS locked.
|
||||||
|
|
||||||
|
A client may remove itself from all direct requests(QueueSendChunkTo()) by calling RemoveClient();
|
||||||
|
this ensures that the client's Send() won't be called anymore by ChunkSender.
|
||||||
|
Note that it may be called by world's BroadcastToChunk() if the client is still in the chunk.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@ -78,10 +82,11 @@ protected:
|
|||||||
|
|
||||||
cWorld * m_World;
|
cWorld * m_World;
|
||||||
|
|
||||||
cCriticalSection m_CS;
|
cCriticalSection m_CS;
|
||||||
cChunkCoordsList m_ChunksReady;
|
cChunkCoordsList m_ChunksReady;
|
||||||
sSendChunkList m_SendChunks;
|
sSendChunkList m_SendChunks;
|
||||||
cEvent m_Event; // Set when anything is added to m_ChunksReady
|
cEvent m_evtQueue; // Set when anything is added to m_ChunksReady
|
||||||
|
cEvent m_evtRemoved; // Set when removed clients are safe to be deleted
|
||||||
|
|
||||||
// Data about the chunk that is being sent:
|
// Data about the chunk that is being sent:
|
||||||
char m_BlockData[cChunk::c_BlockDataSize];
|
char m_BlockData[cChunk::c_BlockDataSize];
|
||||||
|
Loading…
Reference in New Issue
Block a user