From: <man...@us...> - 2014-10-15 14:47:40
|
Revision: 4433 http://sourceforge.net/p/modplug/code/4433 Author: manxorist Date: 2014-10-15 14:47:23 +0000 (Wed, 15 Oct 2014) Log Message: ----------- [Ref] Rename mpt::thread to mpt::UnmanagedThread because its lifetime and management semantics differ considerably from C++11 std::thread. [Ref] Add mpt::thread, a subset implementation of std::thread. The biggest difference is that it is not moveable and thus not useable in all situations where std::thread would be useable. [Ref] Remove the priority parameter to mpt::UnmanagedThread. Provide a free SetThreadPriority() function instead. [Ref] Add MPT_DELEGATE macro which allows for an easy syntax for providing a pointer-to-member and instance tuple to the mpt::thread constructor. [Ref] Convert the update check thread to mpt::thread and MPT_DELEGATE. Modified Paths: -------------- trunk/OpenMPT/common/thread.h trunk/OpenMPT/mptrack/Autotune.cpp trunk/OpenMPT/mptrack/UpdateCheck.cpp trunk/OpenMPT/mptrack/UpdateCheck.h trunk/OpenMPT/mptrack/View_tre.cpp trunk/OpenMPT/mptrack/View_tre.h trunk/OpenMPT/pluginBridge/Bridge.cpp trunk/OpenMPT/pluginBridge/BridgeCommon.h trunk/OpenMPT/pluginBridge/BridgeWrapper.cpp Modified: trunk/OpenMPT/common/thread.h =================================================================== --- trunk/OpenMPT/common/thread.h 2014-10-15 09:35:38 UTC (rev 4432) +++ trunk/OpenMPT/common/thread.h 2014-10-15 14:47:23 UTC (rev 4433) @@ -9,46 +9,368 @@ #pragma once + +#if defined(MODPLUG_TRACKER) + +#if MPT_OS_WINDOWS && MPT_MSVC_BEFORE(2012,0) +// our own +#else +#include <thread> +#endif + OPENMPT_NAMESPACE_BEGIN namespace mpt { -#if defined(WIN32) -// Default WinAPI thread +#if MPT_OS_WINDOWS + +enum ThreadPriority +{ + ThreadPriorityLowest = THREAD_PRIORITY_LOWEST, + ThreadPriorityLower = THREAD_PRIORITY_BELOW_NORMAL, + ThreadPriorityNormal = THREAD_PRIORITY_NORMAL, + ThreadPriorityHigh = THREAD_PRIORITY_ABOVE_NORMAL, + ThreadPriorityHighest = THREAD_PRIORITY_HIGHEST +}; + +#else + +enum ThreadPriority +{ + ThreadPriorityLowest = -2, + ThreadPriorityLower = -1, + ThreadPriorityNormal = 0, + ThreadPriorityHigh = 1, + ThreadPriorityHighest = 2 +}; + +#endif + + + +#if MPT_OS_WINDOWS && MPT_MSVC_BEFORE(2012,0) + + + +typedef HANDLE native_handle_type; + +// std::thread +// NOTE: This implementation is not movable and prevents copying. +// Therefore, it is not as versatile as a full C++11 std::thread implementation. +// It is only a strict subset. class thread { + +private: + + thread(const thread &) {} // = delete + thread & operator = (const thread &) { return *this; } // = delete + +private: + + class functor_helper_base { + protected: + functor_helper_base() {} + public: + virtual ~functor_helper_base() {} + public: + virtual void operator () () = 0; + }; + + template<typename Tfunc> + class functor_helper : public functor_helper_base { + private: + Tfunc func; + public: + functor_helper(Tfunc func_) : func(func_) { return; } + virtual ~functor_helper() { return; } + virtual void operator () () { func(); } + }; + + enum FunctionMode + { + FunctionModeNone = 0, + FunctionModeParamNone = 1, + FunctionModeParamPointer = 2, + FunctionModeFunctor = 3, + }; + + native_handle_type threadHandle; + + // Thread startup accesses members of mpt::thread. + // If the mpt::thread instanced gets detached and destroyed directly after initialization, + // there is a race between thread startup and detach/destroy. + // startupDoneEvent protects against this race. + HANDLE startupDoneEvent; + + FunctionMode functionMode; + union { + struct { + void (*function)(void); + } ModeParamNone; + struct { + void (*function)(void*); + void * userdata; + } ModeParamPointer; + struct { + functor_helper_base * pfunctor; + } ModeFunctor; + } modeState; + +private: + + std::uintptr_t ThreadFuntion() + { + switch(functionMode) + { + case FunctionModeNone: + SetEvent(startupDoneEvent); + return 0; + break; + case FunctionModeParamNone: + { + void (*f)(void) = modeState.ModeParamNone.function; + SetEvent(startupDoneEvent); + f(); + } + return 0; + break; + case FunctionModeParamPointer: + { + void (*f)(void*) = modeState.ModeParamPointer.function; + void * d = modeState.ModeParamPointer.userdata; + SetEvent(startupDoneEvent); + f(d); + } + return 0; + break; + case FunctionModeFunctor: + { + functor_helper_base * pf = modeState.ModeFunctor.pfunctor; + SetEvent(startupDoneEvent); + (*pf)(); + delete pf; + } + return 0; + break; + default: + SetEvent(startupDoneEvent); + return 0; + break; + } + SetEvent(startupDoneEvent); + return 0; + } + + static DWORD WINAPI ThreadFunctionWrapper(LPVOID param) + { + reinterpret_cast<mpt::thread*>(param)->ThreadFuntion(); + return 0; + } + +public: + + mpt::native_handle_type native_handle() + { + return threadHandle; + } + + bool joinable() const + { + return (threadHandle != nullptr); + } + + void join() + { + if(!joinable()) + { + throw std::invalid_argument("thread::joinable() == false"); + } + WaitForSingleObject(threadHandle, INFINITE); + CloseHandle(threadHandle); + threadHandle = nullptr; + } + + void detach() + { + if(!joinable()) + { + throw std::invalid_argument("thread::joinable() == false"); + } + CloseHandle(threadHandle); + threadHandle = nullptr; + } + + thread() + : threadHandle(nullptr) + , startupDoneEvent(nullptr) + , functionMode(FunctionModeNone) + { + std::memset(&modeState, 0, sizeof(modeState)); + } + + thread(void (*function)(void)) + : threadHandle(nullptr) + , startupDoneEvent(nullptr) + , functionMode(FunctionModeParamNone) + { + std::memset(&modeState, 0, sizeof(modeState)); + modeState.ModeParamNone.function = function; + startupDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if(!startupDoneEvent) { throw std::runtime_error("unable to start thread"); } + DWORD dummy = 0; // For Win9x + threadHandle = CreateThread(NULL, 0, ThreadFunctionWrapper, this, 0, &dummy); + if(threadHandle) + { + WaitForSingleObject(startupDoneEvent, INFINITE); + } + CloseHandle(startupDoneEvent); + startupDoneEvent = nullptr; + if(!threadHandle) { throw std::runtime_error("unable to start thread"); } + } + + thread(void (*function)(void*), void * userdata) + : threadHandle(nullptr) + , startupDoneEvent(nullptr) + , functionMode(FunctionModeParamPointer) + { + std::memset(&modeState, 0, sizeof(modeState)); + modeState.ModeParamPointer.function = function; + modeState.ModeParamPointer.userdata = userdata; + startupDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if(!startupDoneEvent) { throw std::runtime_error("unable to start thread"); } + DWORD dummy = 0; // For Win9x + threadHandle = CreateThread(NULL, 0, ThreadFunctionWrapper, this, 0, &dummy); + if(threadHandle) + { + WaitForSingleObject(startupDoneEvent, INFINITE); + } + CloseHandle(startupDoneEvent); + startupDoneEvent = nullptr; + if(!threadHandle) { throw std::runtime_error("unable to start thread"); } + } + + template<typename Tfunctor> + thread(Tfunctor functor) + : threadHandle(nullptr) + , startupDoneEvent(nullptr) + , functionMode(FunctionModeFunctor) + { + std::memset(&modeState, 0, sizeof(modeState)); + modeState.ModeFunctor.pfunctor = new functor_helper<Tfunctor>(functor); + startupDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if(!startupDoneEvent) { throw std::runtime_error("unable to start thread"); } + DWORD dummy = 0; // For Win9x + threadHandle = CreateThread(NULL, 0, ThreadFunctionWrapper, this, 0, &dummy); + if(threadHandle) + { + WaitForSingleObject(startupDoneEvent, INFINITE); + } + CloseHandle(startupDoneEvent); + startupDoneEvent = nullptr; + if(!threadHandle) { throw std::runtime_error("unable to start thread"); } + } + + ~thread() + { + ASSERT(!joinable()); + } + +}; + + + +#else // !(MPT_OS_WINDOWS && MPT_MSVC_BEFORE(2012,0)) + + + +typedef std::thread thread; + + + +#endif // MPT_OS_WINDOWS && MPT_MSVC_BEFORE(2012,0) + + + +template<typename T, void (T::*Func)(void)> +class pointer_to_member_functor { +private: + T *that; +public: + void operator () () + { + (that->*Func)(); + } + pointer_to_member_functor(T *that) + : that(that) + { + return; + } +}; + +// MPT_DELEGATE is a helper to use member functions of classes as thread entry +// points. +// Implementing generic support in the mpt::thread constructor would result +// in horribly unreadable template code when not making use of at least some +// C++11 features. +#define MPT_DELEGATE(type, func, inst) mpt::pointer_to_member_functor< type , & type :: func >( inst ) + + + +#if MPT_OS_WINDOWS + +inline void SetThreadPriority(mpt::thread &t, mpt::ThreadPriority priority) +{ + ::SetThreadPriority(t.native_handle(), priority); +} + +inline void SetCurrentThreadPriority(mpt::ThreadPriority priority) +{ + ::SetThreadPriority(GetCurrentThread(), priority); +} + +#else // !MPT_OS_WINDOWS + +inline void SetThreadPriority(mpt::thread & /*t*/ , mpt::ThreadPriority /*priority*/ ) +{ + // nothing +} + +inline void SetCurrentThreadPriority(mpt::ThreadPriority /*priority*/ ) +{ + // nothing +} + +#endif // MPT_OS_WINDOWS + + + +#if defined(MODPLUG_TRACKER) + +// Default WinAPI thread +class UnmanagedThread +{ protected: HANDLE threadHandle; public: - enum Priority - { - lowest = THREAD_PRIORITY_LOWEST, - lower = THREAD_PRIORITY_BELOW_NORMAL, - normal = THREAD_PRIORITY_NORMAL, - high = THREAD_PRIORITY_ABOVE_NORMAL, - highest = THREAD_PRIORITY_HIGHEST - }; - operator HANDLE& () { return threadHandle; } operator bool () const { return threadHandle != nullptr; } - thread() : threadHandle(nullptr) { } - thread(LPTHREAD_START_ROUTINE function, void *userData = nullptr, Priority priority = normal) + UnmanagedThread() : threadHandle(nullptr) { } + UnmanagedThread(LPTHREAD_START_ROUTINE function, void *userData = nullptr) { - DWORD dummy; // For Win9x + DWORD dummy = 0; // For Win9x threadHandle = CreateThread(NULL, 0, function, userData, 0, &dummy); - SetThreadPriority(threadHandle, priority); } }; - // Thread that operates on a member function template<typename T, void (T::*Fun)()> -class thread_member : public thread +class UnmanagedThreadMember : public mpt::UnmanagedThread { protected: static DWORD WINAPI wrapperFunc(LPVOID param) @@ -59,15 +381,20 @@ public: - thread_member(T *instance, Priority priority = normal) : thread(wrapperFunc, instance, priority) { } + UnmanagedThreadMember(T *instance) : mpt::UnmanagedThread(wrapperFunc, instance) { } }; -#else // !WIN32 +inline void SetThreadPriority(mpt::UnmanagedThread &t, mpt::ThreadPriority priority) +{ + ::SetThreadPriority(t, priority); +} -#error "thread.h is unimplemented on non-WIN32" +#endif // MODPLUG_TRACKER -#endif // !WIN32 + } // namespace mpt OPENMPT_NAMESPACE_END + +#endif // MODPLUG_TRACKER Modified: trunk/OpenMPT/mptrack/Autotune.cpp =================================================================== --- trunk/OpenMPT/mptrack/Autotune.cpp 2014-10-15 09:35:38 UTC (rev 4432) +++ trunk/OpenMPT/mptrack/Autotune.cpp 2014-10-15 14:47:23 UTC (rev 4433) @@ -257,7 +257,7 @@ if(p == numProcs - 1) threadInfo[p].endNote = END_NOTE; - threadHandles[p] = mpt::thread(AutotuneThread, &threadInfo[p]); + threadHandles[p] = mpt::UnmanagedThread(AutotuneThread, &threadInfo[p]); ASSERT(threadHandles[p] != INVALID_HANDLE_VALUE); } Modified: trunk/OpenMPT/mptrack/UpdateCheck.cpp =================================================================== --- trunk/OpenMPT/mptrack/UpdateCheck.cpp 2014-10-15 09:35:38 UTC (rev 4432) +++ trunk/OpenMPT/mptrack/UpdateCheck.cpp 2014-10-15 14:47:23 UTC (rev 4433) @@ -39,8 +39,7 @@ CUpdateCheck *that = new (std::nothrow) CUpdateCheck(autoUpdate); if(that != nullptr) { - mpt::thread threadHandle = mpt::thread_member<CUpdateCheck, &CUpdateCheck::UpdateThread>(that, autoUpdate ? mpt::thread::lower : mpt::thread::normal); - CloseHandle(threadHandle); + mpt::thread(MPT_DELEGATE(CUpdateCheck, UpdateThread, that)).detach(); } } @@ -49,6 +48,12 @@ void CUpdateCheck::UpdateThread() //------------------------------- { + + if(isAutoUpdate) + { + mpt::SetCurrentThreadPriority(mpt::ThreadPriorityLower); + } + const time_t now = time(nullptr); if(isAutoUpdate) Modified: trunk/OpenMPT/mptrack/UpdateCheck.h =================================================================== --- trunk/OpenMPT/mptrack/UpdateCheck.h 2014-10-15 09:35:38 UTC (rev 4432) +++ trunk/OpenMPT/mptrack/UpdateCheck.h 2014-10-15 14:47:23 UTC (rev 4433) @@ -53,7 +53,7 @@ HINTERNET internetHandle, connectionHandle; // Force creation via "new" as we're using "delete this". Use CUpdateCheck::DoUpdateCheck to create an object. - CUpdateCheck::CUpdateCheck(bool autoUpdate) : internetHandle(nullptr), connectionHandle(nullptr), isAutoUpdate(autoUpdate) { } + CUpdateCheck(bool autoUpdate) : internetHandle(nullptr), connectionHandle(nullptr), isAutoUpdate(autoUpdate) { } void UpdateThread(); void Die(CString errorMessage); Modified: trunk/OpenMPT/mptrack/View_tre.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_tre.cpp 2014-10-15 09:35:38 UTC (rev 4432) +++ trunk/OpenMPT/mptrack/View_tre.cpp 2014-10-15 14:47:23 UTC (rev 4433) @@ -148,7 +148,7 @@ { // Set up instrument library monitoring thread m_hWatchDirKillThread = CreateEvent(NULL, FALSE, FALSE, NULL); - watchDirThread = mpt::thread_member<CModTree, &CModTree::MonitorInstrumentLibrary>(this, mpt::thread::lowest); + watchDirThread = mpt::UnmanagedThreadMember<CModTree, &CModTree::MonitorInstrumentLibrary>(this); } MemsetZero(m_tiMidi); MemsetZero(m_tiPerc); @@ -1839,6 +1839,7 @@ void CModTree::MonitorInstrumentLibrary() //--------------------------------------- { + mpt::SetCurrentThreadPriority(mpt::ThreadPriorityLowest); DWORD result; do { Modified: trunk/OpenMPT/mptrack/View_tre.h =================================================================== --- trunk/OpenMPT/mptrack/View_tre.h 2014-10-15 09:35:38 UTC (rev 4432) +++ trunk/OpenMPT/mptrack/View_tre.h 2014-10-15 14:47:23 UTC (rev 4433) @@ -161,7 +161,7 @@ HWND m_hDropWnd; volatile HANDLE m_hWatchDir; HANDLE m_hWatchDirKillThread; - mpt::thread watchDirThread; + mpt::UnmanagedThread watchDirThread; ModItem m_itemDrag; DWORD m_dwStatus; UINT m_nDocNdx, m_nDragDocNdx; Modified: trunk/OpenMPT/pluginBridge/Bridge.cpp =================================================================== --- trunk/OpenMPT/pluginBridge/Bridge.cpp 2014-10-15 09:35:38 UTC (rev 4432) +++ trunk/OpenMPT/pluginBridge/Bridge.cpp 2014-10-15 14:47:23 UTC (rev 4433) @@ -152,9 +152,9 @@ otherProcess.DuplicateFrom(otherProcess_); sigThreadExit.Create(true); - otherThread = mpt::thread_member<PluginBridge, &PluginBridge::RenderThread>(this); + otherThread = mpt::UnmanagedThreadMember<PluginBridge, &PluginBridge::RenderThread>(this); - mpt::thread_member<PluginBridge, &PluginBridge::MessageThread>(this); + mpt::UnmanagedThreadMember<PluginBridge, &PluginBridge::MessageThread>(this); } Modified: trunk/OpenMPT/pluginBridge/BridgeCommon.h =================================================================== --- trunk/OpenMPT/pluginBridge/BridgeCommon.h 2014-10-15 09:35:38 UTC (rev 4432) +++ trunk/OpenMPT/pluginBridge/BridgeCommon.h 2014-10-15 14:47:23 UTC (rev 4433) @@ -434,7 +434,7 @@ // Signals for internal communication (wake up waiting threads). Confirm() => OK, Send() => Failure Signal ackSignals[SharedMemLayout::queueSize]; - mpt::thread otherThread; // Handle of the "other" thread (host side: message thread, bridge side: process thread) + mpt::UnmanagedThread otherThread; // Handle of the "other" thread (host side: message thread, bridge side: process thread) Event otherProcess; // Handle of "other" process (host handle in the bridge and vice versa) Event sigThreadExit; // Signal to kill helper thread Modified: trunk/OpenMPT/pluginBridge/BridgeWrapper.cpp =================================================================== --- trunk/OpenMPT/pluginBridge/BridgeWrapper.cpp 2014-10-15 09:35:38 UTC (rev 4432) +++ trunk/OpenMPT/pluginBridge/BridgeWrapper.cpp 2014-10-15 14:47:23 UTC (rev 4433) @@ -209,7 +209,7 @@ sigThreadExit.Create(true); sigAutomation.Create(true); - otherThread = mpt::thread_member<BridgeWrapper, &BridgeWrapper::MessageThread>(this); + otherThread = mpt::UnmanagedThreadMember<BridgeWrapper, &BridgeWrapper::MessageThread>(this); BridgeMessage initMsg; initMsg.Init(pluginPath.ToWide().c_str(), MIXBUFFERSIZE, ExceptionHandler::fullMemDump); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |