diff options
author | Tiger Wang <ziwei.tiger@outlook.com> | 2021-03-28 23:33:24 +0200 |
---|---|---|
committer | Tiger Wang <ziwei.tiger@outlook.com> | 2021-03-30 00:36:15 +0200 |
commit | 222d9957a1a566464d6a824caaf9a56539eb3234 (patch) | |
tree | c4bd9041e07a61c6f1a1eaaf70838e26fafae82e | |
parent | Do an early check for empty network buffers (#5172) (diff) | |
download | cuberite-222d9957a1a566464d6a824caaf9a56539eb3234.tar cuberite-222d9957a1a566464d6a824caaf9a56539eb3234.tar.gz cuberite-222d9957a1a566464d6a824caaf9a56539eb3234.tar.bz2 cuberite-222d9957a1a566464d6a824caaf9a56539eb3234.tar.lz cuberite-222d9957a1a566464d6a824caaf9a56539eb3234.tar.xz cuberite-222d9957a1a566464d6a824caaf9a56539eb3234.tar.zst cuberite-222d9957a1a566464d6a824caaf9a56539eb3234.zip |
-rw-r--r-- | Tools/MCADefrag/MCADefrag.cpp | 2 | ||||
-rw-r--r-- | src/DeadlockDetect.cpp | 14 | ||||
-rw-r--r-- | src/DeadlockDetect.h | 2 | ||||
-rw-r--r-- | src/OSSupport/IsThread.cpp | 121 | ||||
-rw-r--r-- | src/OSSupport/IsThread.h | 45 | ||||
-rw-r--r-- | src/Server.cpp | 3 |
6 files changed, 92 insertions, 95 deletions
diff --git a/Tools/MCADefrag/MCADefrag.cpp b/Tools/MCADefrag/MCADefrag.cpp index 544d9f9e8..6573fa5ea 100644 --- a/Tools/MCADefrag/MCADefrag.cpp +++ b/Tools/MCADefrag/MCADefrag.cpp @@ -86,7 +86,7 @@ void cMCADefrag::Run(void) // Wait for all the threads to finish: while (!m_Threads.empty()) { - m_Threads.front()->Wait(); + m_Threads.front()->Stop(); delete m_Threads.front(); m_Threads.pop_front(); } diff --git a/src/DeadlockDetect.cpp b/src/DeadlockDetect.cpp index 776ae5b26..3f47589d8 100644 --- a/src/DeadlockDetect.cpp +++ b/src/DeadlockDetect.cpp @@ -51,18 +51,18 @@ cDeadlockDetect::~cDeadlockDetect() -bool cDeadlockDetect::Start(int a_IntervalSec) +void cDeadlockDetect::Start(int a_IntervalSec) { m_IntervalSec = a_IntervalSec; // Read the initial world data: cRoot::Get()->ForEachWorld([=](cWorld & a_World) - { - SetWorldAge(a_World.GetName(), a_World.GetWorldAge()); - return false; - } - ); - return Super::Start(); + { + SetWorldAge(a_World.GetName(), a_World.GetWorldAge()); + return false; + }); + + Super::Start(); } diff --git a/src/DeadlockDetect.h b/src/DeadlockDetect.h index a2ec1823f..98ce13df3 100644 --- a/src/DeadlockDetect.h +++ b/src/DeadlockDetect.h @@ -31,7 +31,7 @@ public: virtual ~cDeadlockDetect() override; /** Starts the detection. Hides cIsThread's Start, because we need some initialization */ - bool Start(int a_IntervalSec); + void Start(int a_IntervalSec); /** Adds the critical section for tracking. Tracked CSs are listed, together with ownership details, when a deadlock is detected. diff --git a/src/OSSupport/IsThread.cpp b/src/OSSupport/IsThread.cpp index a79fee9c6..28ed327f1 100644 --- a/src/OSSupport/IsThread.cpp +++ b/src/OSSupport/IsThread.cpp @@ -32,62 +32,58 @@ cIsThread::~cIsThread() -void cIsThread::DoExecute(void) +void cIsThread::Start(void) { -#if defined(_MSC_VER) && !defined(NDEBUG) - /* Sets the name of this thread. - (When in MSVC, the debugger provides "thread naming" by catching special exceptions) - Code adapted from MSDN: https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */ + // Initialize the thread: + m_Thread = std::thread(&cIsThread::Entrypoint, this); -#pragma pack(push, 8) - struct THREADNAME_INFO - { - DWORD dwType; // Must be 0x1000. - LPCSTR szName; // Pointer to name (in user addr space). - DWORD dwThreadID; // Thread ID (-1 = caller thread). - DWORD dwFlags; // Reserved for future use, must be zero. - }; -#pragma pack(pop) + // Notify the thread that initialization is complete and it can run its code safely: + m_Initialisation.Set(); +} - if (!m_ThreadName.empty()) - { - const DWORD NAME_EXCEPTION = 0x406D1388; - const THREADNAME_INFO Name = { 0x1000, m_ThreadName.c_str(), -1, 0 }; - __try - { - RaiseException(NAME_EXCEPTION, 0, sizeof(Name) / sizeof(ULONG_PTR), reinterpret_cast<const ULONG_PTR *>(&Name)); - } - __except (EXCEPTION_EXECUTE_HANDLER) + + + +void cIsThread::Stop(void) +{ + m_ShouldTerminate = true; + { + LOGD("Waiting for the %s thread to finish", m_ThreadName.c_str()); + if (m_Thread.joinable()) { + m_Thread.join(); } + LOGD("The %s thread finished", m_ThreadName.c_str()); } -#endif - - m_evtStart.Wait(); - Execute(); + m_ShouldTerminate = false; } -bool cIsThread::Start(void) +void cIsThread::Entrypoint(void) { - try - { - // Initialize the thread: - m_Thread = std::thread(&cIsThread::DoExecute, this); + // Apply thread naming: + SetThreadName(); - // Notify the thread that initialization is complete and it can run its code safely: - m_evtStart.Set(); + // Wait for initialisation: + m_Initialisation.Wait(); - return true; + try + { + Execute(); } - catch (const std::system_error & a_Exception) + catch (const std::exception & Oops) { - LOGERROR("cIsThread::Start error %i: could not construct thread %s; %s", a_Exception.code().value(), m_ThreadName.c_str(), a_Exception.code().message().c_str()); - return false; + LOGERROR("Thread %s faulted with standard exception: %s", m_ThreadName.c_str(), Oops.what()); + std::abort(); + } + catch (...) + { + LOGERROR("Thread %s faulted with unknown exception!", m_ThreadName.c_str()); + std::abort(); } } @@ -95,34 +91,37 @@ bool cIsThread::Start(void) -void cIsThread::Stop(void) +void cIsThread::SetThreadName() const { - m_ShouldTerminate = true; - Wait(); - m_ShouldTerminate = false; -} - +#if defined(_MSC_VER) && !defined(NDEBUG) + /* Sets the name of this thread. + (When in MSVC, the debugger provides "thread naming" by catching special exceptions) + Code adapted from MSDN: https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */ + if (m_ThreadName.empty()) + { + return; + } +#pragma pack(push, 8) + struct THREADNAME_INFO + { + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to name (in user addr space). + DWORD dwThreadID; // Thread ID (-1 = caller thread). + DWORD dwFlags; // Reserved for future use, must be zero. + }; +#pragma pack(pop) + const DWORD NAME_EXCEPTION = 0x406D1388; + const THREADNAME_INFO Name = { 0x1000, m_ThreadName.c_str(), -1, 0 }; -bool cIsThread::Wait(void) -{ - LOGD("Waiting for the %s thread to finish", m_ThreadName.c_str()); - if (m_Thread.joinable()) + __try { - try - { - m_Thread.join(); - return true; - } - catch (const std::system_error & a_Exception) - { - LOGERROR("%s error %i: could not join the %s thread; %s", __FUNCTION__, a_Exception.code().value(), m_ThreadName.c_str(), a_Exception.code().message().c_str()); - return false; - } + RaiseException(NAME_EXCEPTION, 0, sizeof(Name) / sizeof(ULONG_PTR), reinterpret_cast<const ULONG_PTR *>(&Name)); } - - LOGD("The %s thread finished", m_ThreadName.c_str()); - return true; + __except (EXCEPTION_EXECUTE_HANDLER) + { + } +#endif } diff --git a/src/OSSupport/IsThread.h b/src/OSSupport/IsThread.h index 6a515a6de..4c2131d24 100644 --- a/src/OSSupport/IsThread.h +++ b/src/OSSupport/IsThread.h @@ -2,11 +2,10 @@ // IsThread.h // Interfaces to the cIsThread class representing an OS-independent wrapper for a class that implements a thread. -// This class will eventually suupersede the old cThread class /* Usage: -To have a new thread, declare a class descending from cIsClass. +To have a new thread, declare a class descending from cIsThread. Then override its Execute() method to provide your thread processing. In the descending class' constructor call the Start() method to start the thread once you're finished with initialization. */ @@ -23,46 +22,44 @@ In the descending class' constructor call the Start() method to start the thread class cIsThread { -protected: - /** This is the main thread entrypoint. - This function, overloaded by the descendants, is called in the new thread. */ - virtual void Execute(void) = 0; - - /** The overriden Execute() method should check this value periodically and terminate if this is true. */ - std::atomic<bool> m_ShouldTerminate; - public: + cIsThread(AString && a_ThreadName); virtual ~cIsThread(); /** Starts the thread; returns without waiting for the actual start. */ - bool Start(void); + void Start(void); /** Signals the thread to terminate and waits until it's finished. */ void Stop(void); - /** Waits for the thread to finish. Doesn't signalize the ShouldTerminate flag. */ - bool Wait(void); - /** Returns true if the thread calling this function is the thread contained within this object. */ bool IsCurrentThread(void) const { return std::this_thread::get_id() == m_Thread.get_id(); } -private: +protected: - /** The name of the thread, used to aid debugging in IDEs which support named threads */ - AString m_ThreadName; + /** This function, overloaded by the descendants, is called in the new thread. */ + virtual void Execute(void) = 0; + + /** The overriden Execute() method should check this value periodically and terminate if this is true. */ + std::atomic<bool> m_ShouldTerminate; + +private: /** The thread object which holds the created thread for later manipulation */ std::thread m_Thread; + /** The name of the thread, used to aid debugging in IDEs which support named threads */ + AString m_ThreadName; + /** The event that is used to wait with the thread's execution until the thread object is fully initialized. This prevents the IsCurrentThread() call to fail because of a race-condition where the thread starts before m_Thread has been fully assigned. */ - cEvent m_evtStart; - - /** Wrapper for Execute() that waits for the initialization event, to prevent race conditions in thread initialization. */ - void DoExecute(void); -} ; - - + cEvent m_Initialisation; + /** This is the main thread entrypoint. + Wrapper for Execute() that waits for the initialization event, to prevent race conditions in thread initialization. */ + void Entrypoint(void); + /** Sets the name of the current thread to be the name provided in m_ThreadName. */ + void SetThreadName() const; +} ; diff --git a/src/Server.cpp b/src/Server.cpp index a0b9f245d..7e7aa0c67 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -411,7 +411,8 @@ bool cServer::Start(void) LOGERROR("Couldn't open any ports. Aborting the server"); return false; } - return m_TickThread.Start(); + m_TickThread.Start(); + return true; } |