43#ifndef LASS_GUARDIAN_OF_INCLUSION_UTIL_IMPL_THREAD_WIN32_INL
44#define LASS_GUARDIAN_OF_INCLUSION_UTIL_IMPL_THREAD_WIN32_INL
54#define WIN32_LEAN_AND_MEAN
58#if LASS_PLATFORM_TYPE == LASS_PLATFORM_TYPE_WIN32
60# pragma warning(disable: 4239)
61# pragma warning(disable: 4267)
62# pragma warning(disable: 4996)
72TCpuSet availableProcessors()
74 DWORD_PTR processAffinityMask, systemAffinityMask;
75 LASS_ENFORCE_WINAPI(GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask));
79 while (systemAffinityMask)
82 systemAffinityMask >>= 1;
86 TCpuSet cpuSet(n,
false);
87 for (
size_t i = 0; i < n; ++i)
98class MutexInternal: NonCopyable
104 mutex_ = LASS_ENFORCE_WINAPI(::CreateMutex(NULL, FALSE, NULL));
109 LASS_ASSERT(lockCount_ == 0);
110 const BOOL ret = CloseHandle(mutex_);
111 LASS_ASSERT(ret != 0);
114 const unsigned lastError = impl::lass_GetLastError();
115 std::cerr <<
"[LASS RUN MSG] WARNING: CloseHandle failed in ~MutexInternal(): ("
116 << lastError <<
") " << impl::lass_FormatMessage(lastError) << std::endl;
121 const DWORD ret = WaitForSingleObject(mutex_, INFINITE);
127 std::cerr <<
"[LASS RUN MSG] UNDEFINED BEHAVIOUR WARNING: "
128 <<
"WaitForSingleObject returned with WAIT_ABANDONED. "
129 <<
"Going to take ownership and continue happily." << std::endl;
136 const unsigned lastError = impl::lass_GetLastError();
137 LASS_THROW(
"WaitForSingleObject failed: (" << lastError <<
") "
138 << impl::lass_FormatMessage(lastError));
142 LASS_THROW(
"impossible return value of WaitForSingleObject: " << ret);
148 const DWORD ret = WaitForSingleObject(mutex_, 0);
154 std::cerr <<
"[LASS RUN MSG] UNDEFINED BEHAVIOUR WARNING: "
155 <<
"WaitForSingleObject returned with WAIT_ABANDONED. "
156 <<
"Going to take ownership and continue happily." << std::endl;
163 const unsigned lastError = impl::lass_GetLastError();
164 LASS_THROW(
"WaitForSingleObject failed: (" << lastError <<
") "
165 << impl::lass_FormatMessage(lastError));
170 LASS_THROW(
"impossible return value of WaitForSingleObject: " << ret);
177 LASS_ASSERT(lockCount_ > 0);
180 LASS_THROW(
"attempting to unlock an unlocked mutex");
183 LASS_ENFORCE_WINAPI(ReleaseMutex(mutex_));
185 unsigned lockCount()
const
199class CriticalSectionInternal: NonCopyable
202 CriticalSectionInternal()
204 InitializeCriticalSection(&criticalSection_);
206 ~CriticalSectionInternal()
208 LASS_ASSERT(criticalSection_.LockCount == -1);
209 DeleteCriticalSection(&criticalSection_);
213 EnterCriticalSection(&criticalSection_);
221 LASS_ASSERT(criticalSection_.RecursionCount > 0);
222 LeaveCriticalSection(&criticalSection_);
224 unsigned lockCount()
const
226 return criticalSection_.RecursionCount;
229 CRITICAL_SECTION criticalSection_;
237class ConditionInternal: NonCopyable
243 event_ = LASS_ENFORCE_WINAPI(::CreateEvent(
252 const BOOL ret = CloseHandle(event_);
253 LASS_ASSERT(ret != 0);
256 const unsigned lastError = impl::lass_GetLastError();
257 std::cerr <<
"[LASS RUN MSG] UNDEFINED BEHAVIOUR WARNING: "
258 <<
" CloseHandle failed in ~MutexInternal(): ("
259 << lastError <<
") " << impl::lass_FormatMessage(lastError) << std::endl;
271 ::InterlockedIncrement(&threadsWaiting_);
274 const DWORD ret = WaitForSingleObject(event_, iMilliSeconds);
275 ::InterlockedDecrement(&threadsWaiting_);
285 const unsigned lastError = impl::lass_GetLastError();
286 LASS_THROW(
"WaitForSingleObject failed: (" << lastError <<
") "
287 << impl::lass_FormatMessage(lastError));
290 LASS_THROW(
"impossible return value of WaitForSingleObject: " << ret);
300 LASS_ENFORCE_WINAPI(::SetEvent(event_));
307 LONG nWaiters = threadsWaiting_;
312 for ( LONG n = 0; n < nWaiters; ++n )
317 LONG threadsWaiting_;
325class ThreadLocalStorageInternal: NonCopyable
328 typedef void (*TDestructor)(
void*);
330 ThreadLocalStorageInternal(
void (*destructor)(
void*))
333 if (index_ == TLS_OUT_OF_INDEXES)
335 const unsigned lastError = impl::lass_GetLastError();
336 LASS_THROW(
"Failed to allocate thread local storage: TlsAlloc failed: ("
337 << lastError <<
") " << impl::lass_FormatMessage(lastError));
339 if (TDestructors* destrs = destructors())
343 (*destrs)[index_] = destructor;
354 LASS_THROW(
"Failed to allocate thread local storage: dead destructor singleton");
357 ~ThreadLocalStorageInternal()
359 if (TDestructors* destrs = destructors())
361 destrs->erase(index_);
367 void* result = TlsGetValue(index_);
373 return LASS_ENFORCE_WINAPI(result)(
"Failed to get thread local storage value");
377 void set(
void* value)
379 LASS_ENFORCE_WINAPI(TlsSetValue(index_, value))(
"Failed to set thread local storage value");
385 static void destructLocals()
387 if (TDestructors* destrs = destructors())
389 for (TDestructors::iterator i = destrs->begin(); i != destrs->end(); ++i)
391 DWORD index = i->first;
392 TDestructor destructor = i->second;
395 if (
void* p = TlsGetValue(index))
398 TlsSetValue(index, 0);
407 typedef std::map<DWORD, TDestructor> TDestructors;
409 void freeSlot(DWORD index)
413 const unsigned lastError = impl::lass_GetLastError();
414 std::cerr <<
"[LASS RUN MSG] UNDEFINED BEHAVIOUR WARNING: TlsFree failed: ("
415 << lastError <<
") " << impl::lass_FormatMessage(lastError) << std::endl;
419 static TDestructors* destructors()
424 static TDestructors* forceIntoExistance;
430ThreadLocalStorageInternal::TDestructors* ThreadLocalStorageInternal::forceIntoExistance =
431 ThreadLocalStorageInternal::destructors();
441class MainLocalStorageDestroyer: NonCopyable
444 ~MainLocalStorageDestroyer()
446 ThreadLocalStorageInternal::destructLocals();
449 static MainLocalStorageDestroyer* forceIntoExistance;
452MainLocalStorageDestroyer* MainLocalStorageDestroyer::forceIntoExistance =
460DWORD_PTR bindThread(HANDLE thread,
size_t processor)
462 DWORD_PTR affinityMask = 0;
465 DWORD_PTR processAffinityMask, systemAffinityMask;
466 LASS_ENFORCE_WINAPI(GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask));
467 affinityMask = systemAffinityMask;
473 LASS_ENFORCE_WINAPI(SetThreadAffinityMask(thread, affinityMask))
474 (
"Failed to bind thread to processor ")(processor);
476 const DWORD_PTR threadAffinity = LASS_ENFORCE_WINAPI(SetThreadAffinityMask(thread, affinityMask));
477 LASS_ENFORCE(threadAffinity == affinityMask);
478 return threadAffinity;
481void setThreadName(DWORD threadId,
const char* threadName)
484 strncpy(buffer, threadName, 10);
487 struct THREADNAME_INFO
495 THREADNAME_INFO info;
496 info.dwType = 0x1000;
497 info.szName = threadName;
498 info.dwThreadID = threadId;
503 RaiseException(0x406D1388, 0,
sizeof(info)/
sizeof(DWORD), (ULONG_PTR*)&info);
505 __except(EXCEPTION_CONTINUE_EXECUTION)
512#define LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(exception_type)\
513 catch (const exception_type& error)\
515 pimpl->error_.reset(new RemoteExceptionWrapper<exception_type>(error));\
521class ThreadInternal: NonCopyable
525 ThreadInternal(Thread& iThread,
ThreadKind iKind,
const char* name):
543 LASS_THROW(
"You can run a thread only once");
545 handle_ = (HANDLE) _beginthreadex(NULL, 0, &ThreadInternal::startThread,
this, 0, &id_);
549 LASS_THROW(
"_beginthreadex failed: (" << errnum <<
") " <<
lass_strerror(errnum));
553 setThreadName(id_, name_);
555 runCondition_.wait();
558 bool isJoinable()
const
560 return isJoinable_ && isCreated_;
567 LASS_THROW(
"Can not wait for uncreated or detached threads");
569 const DWORD ret = WaitForSingleObject(handle_, INFINITE);
577 const unsigned lastError = impl::lass_GetLastError();
578 LASS_THROW(
"WaitForSingleObject failed: (" << lastError <<
") "
579 << impl::lass_FormatMessage(lastError));
582 LASS_THROW(
"impossible return value of WaitForSingleObject: " << ret);
591 void bind(
size_t processor)
593 affinity_ = bindThread(handle_, processor);
596 const TCpuSet affinity()
const
600 for (
size_t i = 0; i < n; ++i)
607 static void sleep(
unsigned long iMilliSeconds)
609 Sleep(iMilliSeconds);
617 static void bindCurrent(
size_t processor)
619 bindThread(GetCurrentThread(), processor);
623 static unsigned __stdcall startThread(
void* iPimpl)
626 ThreadInternal* pimpl =
static_cast<ThreadInternal*
>(iPimpl);
628 GetProcessAffinityMask(GetCurrentProcess(), &pimpl->affinity_, &dummy);
629 pimpl->isCreated_ =
true;
630 if (pimpl->isJoinable_)
634 pimpl->runCondition_.signal();
635 pimpl->thread_.doRun();
637 catch (
const RemoteExceptionBase& error)
639 pimpl->error_ = error.clone();
641 LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::domain_error)
642 LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::invalid_argument)
643 LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::length_error)
644 LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::out_of_range)
645 LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::range_error)
646 LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::overflow_error)
647 LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::underflow_error)
648 LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::runtime_error)
649 LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::logic_error)
650 LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::exception)
654 pimpl->runCondition_.signal();
655 pimpl->thread_.doRun();
656 delete &pimpl->thread_;
661 static void onThreadDetach()
663 ThreadLocalStorageInternal::destructLocals();
671 TRemoteExceptionBasePtr error_;
672 Condition runCondition_;
675 volatile bool isJoinable_;
676 volatile bool isCreated_;
684#if LASS_PLATFORM_TYPE == LASS_PLATFORM_TYPE_WIN32
690#include "../dll/dll_main.h"
699BOOL threadDllMain(HINSTANCE, DWORD dwReason, LPVOID)
703 case DLL_PROCESS_DETACH:
704 case DLL_THREAD_DETACH:
705 lass::util::impl::ThreadInternal::onThreadDetach();
714LASS_EXECUTE_BEFORE_MAIN_EX(
715 lassUtilImplThreadWin32RegisterDllMain,
716 ::lass::dll::registerDllMain(::lass::util::impl::threadDllMain);
724void NTAPI lassOnThreadCallback(PVOID, DWORD dwReason, PVOID)
726 if(dwReason == DLL_THREAD_DETACH)
728 lass::util::impl::ThreadInternal::onThreadDetach();
733# pragma section(".CRT$XLB", read)
735# pragma section(".CRT$XLB", read, write)
738extern "C" __declspec(allocate(
".CRT$XLB")) PIMAGE_TLS_CALLBACK lassThreadCallback = lassOnThreadCallback;
743# pragma comment(linker, "/INCLUDE:_tls_used")
745# pragma comment(linker, "/INCLUDE:__tls_used")
static TInstance * instance()
Return pointer to singleton instance.
static constexpr size_t anyProcessor
argument for Thread::bind to unbind the thread so it runs on any processor
bool checkBit(T a_bits, size_t a_bit)
return true if a bit is set high.
void setBit(T &a_bits, size_t a_bit)
Set a bit high.
const std::string lass_strerror(int errnum)
returns message associated to an CLIB error code
int lass_errno()
returns CLIB errno
LockResult
Return code for lock functions.
size_t numberOfProcessors()
Return highest id of processor + 1, in this machine.
WaitResult
Return code for wait functions.
@ threadJoinable
joinable thread, can be waited for
@ lockSuccess
Mutex/CriticalSection is succesfully locked by this thread.
@ lockBusy
Mutex/CriticalSection is locked by another thread.
@ waitSuccess
Wait is successfully terminated.
@ waitTimeout
Wait failed because of a timeout.
general utility, debug facilities, ...
Library for Assembled Shared Sources.