#include "thread.hpp" #include "../time/time.hpp" #include "../common/compat.hpp" namespace ThreadStatic { static DWORD WINAPI EntryPoint(LPVOID data) { sprawl::threading::Thread* thread = reinterpret_cast<sprawl::threading::Thread*>(data); sprawl::threading::RunThread(thread); return 0; } } /*static*/ sprawl::threading::ThreadDestructionBehavior sprawl::threading::Thread::ms_defaultDestructionBehavior = sprawl::threading::ThreadDestructionBehavior::Abort; int64_t sprawl::threading::Handle::GetUniqueId() const { return GetThreadId(m_thread); } void sprawl::threading::Thread::Start() { m_handle.GetNativeHandle() = CreateThread( nullptr, 0, &ThreadStatic::EntryPoint, this, 0, nullptr); if(m_handle.GetNativeHandle() != INVALID_HANDLE_VALUE) { if(m_threadName != nullptr) { const DWORD MS_VC_EXCEPTION = 0x406D1388; #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) THREADNAME_INFO info; info.dwType = 0x1000; info.szName = m_threadName; info.dwThreadID = GetThreadId(m_handle.GetNativeHandle()); info.dwFlags = 0; __try { RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); } __except(EXCEPTION_EXECUTE_HANDLER) { } } } } void sprawl::threading::Thread::PlatformJoin() { WaitForSingleObject(m_handle.GetNativeHandle(), INFINITE); } void sprawl::threading::Thread::PlatformDetach() { CloseHandle(m_handle.GetNativeHandle()); } sprawl::threading::Handle sprawl::this_thread::GetHandle() { return sprawl::threading::Handle(GetCurrentThread()); } sprawl::threading::Thread::~Thread() { if(m_destructionBehavior == ThreadDestructionBehavior::Default) { m_destructionBehavior = ms_defaultDestructionBehavior; } if(Joinable()) { #if SPRAWL_EXCEPTIONS_ENABLED if(m_exception) { try { std::rethrow_exception(m_exception); } catch(std::exception& e) { fprintf(stderr, "Thread %" SPRAWL_I64FMT "d destroyed without being joined after thread was terminated with a std::exception. e.what(): %s\n", GetHandle().GetUniqueId(), e.what()); } catch(...) { fprintf(stderr, "Thread %" SPRAWL_I64FMT "d destroyed without being joined after thread was terminated with an exception of unknown type.\n", GetHandle().GetUniqueId()); } fflush(stderr); std::terminate(); } #endif switch(m_destructionBehavior) { case ThreadDestructionBehavior::Abort: case ThreadDestructionBehavior::Default: default: std::terminate(); break; case ThreadDestructionBehavior::Detach: PlatformDetach(); break; case ThreadDestructionBehavior::Join: PlatformJoin(); break; } } CloseHandle(m_handle.GetNativeHandle()); } void sprawl::this_thread::Sleep(uint64_t nanoseconds) { ::Sleep(nanoseconds / sprawl::time::Resolution::Milliseconds); } void sprawl::this_thread::SleepUntil(uint64_t nanosecondTimestamp) { Sleep(nanosecondTimestamp - sprawl::time::Now(sprawl::time::Resolution::Nanoseconds)); } void sprawl::this_thread::Yield() { SwitchToThread(); }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#4 | 16768 | ShadauxCat |
Improvements to error handling in builds with exceptions disabled: - In debug builds or with SPRAWL_ERRORSTATE_STRICT enabled, ErrorState will output a message to stderr and terminate if Get() is called when an error flag is set. (In release buils or with SPRAWL_ERRORSTATE_PERMISSIVE defined, Get() will return junk memory in this case.) - In debug builds or with SPRAWL_ERRORSTATE_STRICT enabled, ErrorState will output a message to stderr and terminate if its destructor is called without checking the errorstate if an error is present (equivalent to an exception terminating the application if no catch() block is present for it). - On linux builds and when running "Analyze" through visual studio, a warning will be issued if any function returning ErrorState has its return value ignored. (This only applies to builds with exceptions not enabled; when exceptions are enabled no warning is issued) - Many functions that could return ErrorState were having their return values silently ignored in internal sprawl code so the user would not find out about errors if exceptions are disabled; now anything in sprawl code that calls a function returning ErrorState will either handle the error, or (in most cases) surface it back up to the user. - As a positive side-effect of the warnings for ignoring ErrorState, several constructors that were capable of throwing exceptions are no longer capable of doing so. #review-16769 |
||
#3 | 16131 | ShadauxCat |
- Exposed FILE* object in sprawl::filesystem::File - Added ability to specify flush behavior for custom handlers via std::function (interesting note - apparently with optimization enabled, calls to std::function can execute faster than virtual function calls) - Threads that destruct with no Join() after exiting with an uncaught exception will terminate with an error message rather than swallowing the exception and letting it disappear #review-16132 |
||
#2 | 16111 | ShadauxCat |
- Threads can now optionally catch exceptions to be rethrown on another thread when it calls Join(). The exception state of a thread can also be queried via HasException() - if this returns true, the thread exited due to an uncaught exception that will be rethrown on Join(). - The behavior of the thread destructor can now be manipulated via SetDestructionBehavior(). By default, a thread whose destructor is called without Join() being called on it will call std::terminate(). But that behavior can be changed such that the destructor can either call Join() automatically, or detach the thread, if it destructs without Join() being called. (If it calls Join() on a thread that caught an exception, the exception will NOT be rethrown, it will be lost to the aether. Throwing exceptions in a destructor is bad, but I'm on the fence whether this should just throw those exceptions away or call std::terminate() in that case. Open for input.) #review-16112 |
||
#1 | 13650 | ShadauxCat |
- Windows implementations of thread and time libraries - Added coroutines - Added some more unit tests, fixed some unit tests in windows environments - Fixed an issue where multi threading was not properly detected on Linux - Fixed the makefiles to build with threading by default on linux - Changed the pool allocator to use thread-local pools instead of locking mutexes - Fixed output of sprawl::string in the StringBuilder library to take length into account - Added string builder options for StringLiteral - Added thread local implementation #review |