Fix race conditions in frontend service send task

ryzomclassic-develop
kaetemi 3 years ago
parent b33ff3cb93
commit 77f92c72a9
No known key found for this signature in database
GPG Key ID: 9873C4D40BB479BC

@ -66,6 +66,9 @@
# include <windows.h> # include <windows.h>
#endif // NL_OS_WINDOWS #endif // NL_OS_WINDOWS
#include <mutex>
#include <condition_variable>
using namespace std; using namespace std;
using namespace NLNET; using namespace NLNET;
using namespace NLMISC; using namespace NLMISC;
@ -236,33 +239,50 @@ void flushMessagesToSend()
class CSendRunnable : public IRunnable class CSendRunnable : public IRunnable
{ {
public: public:
CSendRunnable() : m_StopThread(false), m_SendBuffer(false) {}
CSendRunnable() : StopThread(false), SendBuffer(false) {} virtual void run()
volatile bool StopThread;
volatile bool SendBuffer;
virtual void run()
{ {
while (!StopThread) for (;;)
{ {
while (!StopThread && !SendBuffer) {
nlSleep(1); // FIXME: Use thread event instead. This is only called once per tick, so no need to heat up the CPU here either std::unique_lock<std::mutex> lock(m_Mutex);
m_CondVar.wait(lock, [&]() -> bool { return m_StopThread || m_SendBuffer; });
if (StopThread) m_SendBuffer = false;
break; if (m_StopThread)
{
SendBuffer = false; m_StopThread = false;
return;
}
}
flushMessagesToSend(); flushMessagesToSend();
} }
}
StopThread = false; void sendBuffer()
{
std::unique_lock<std::mutex> lock(m_Mutex);
m_SendBuffer = true;
m_CondVar.notify_one();
}
void stopThread()
{
std::unique_lock<std::mutex> lock(m_Mutex);
m_StopThread = true;
m_CondVar.notify_one();
} }
private:
bool m_StopThread;
bool m_SendBuffer;
std::condition_variable m_CondVar;
std::mutex m_Mutex;
}; };
CSendRunnable SendTask; CSendRunnable *SendTask;
IThread* SendThread = NULL; IThread *SendThread;
/* /*
* Receive task * Receive task
@ -1138,7 +1158,7 @@ inline void CFrontEndService::onTick()
fillPrioritizedActionsToSend(); fillPrioritizedActionsToSend();
swapSendBuffers(); // waits for the end of flushMessagesToSend using the boolean FlushInProgress (with addWait there would be a deadlock at the beginning) swapSendBuffers(); // waits for the end of flushMessagesToSend using the boolean FlushInProgress (with addWait there would be a deadlock at the beginning)
SendTask.SendBuffer = true; SendTask->sendBuffer();
if (SendThread == NULL) if (SendThread == NULL)
{ {
@ -1328,7 +1348,8 @@ void CFrontEndService::init()
{ {
// Init send thread // Init send thread
nlinfo("UseSendThread on, initialise send thread"); nlinfo("UseSendThread on, initialise send thread");
SendThread = IThread::create(&SendTask); SendTask = new CSendRunnable();
SendThread = IThread::create(SendTask);
SendThread->start(); SendThread->start();
} }
@ -1379,7 +1400,10 @@ void CFrontEndService::postInit()
*/ */
void CFrontEndService::release() void CFrontEndService::release()
{ {
SendTask.StopThread = true; if (SendTask)
{
SendTask->stopThread();
}
_ReceiveSub.release(); _ReceiveSub.release();
@ -1402,12 +1426,15 @@ void CFrontEndService::release()
{ {
nlinfo("Release send thread, waiting for task to terminate"); nlinfo("Release send thread, waiting for task to terminate");
// stop send thread // stop send thread
while (SendTask.StopThread) while (SendThread->isRunning()) // FIXME: Implement thread.join()
nlSleep(1); nlSleep(1);
delete SendThread; delete SendThread;
SendThread = NULL; SendThread = NULL;
} }
delete SendTask;
SendTask = NULL;
} }

Loading…
Cancel
Save