00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 #ifndef LASS_GUARDIAN_OF_INCLUSION_UTIL_IMPL_THREAD_WIN32_INL
00044 #define LASS_GUARDIAN_OF_INCLUSION_UTIL_IMPL_THREAD_WIN32_INL
00045
00046 #pragma LASS_NOTE("util::Threading: using win32 implementation")
00047
00048 #include "../util_common.h"
00049 #include "../thread.h"
00050 #include "../singleton.h"
00051 #include "../environment.h"
00052 #include "../bit_manip.h"
00053 #include "lass_errno.h"
00054
00055 #define NOMINMAX
00056 #define WIN32_LEAN_AND_MEAN
00057 #include <process.h>
00058 #include <windows.h>
00059
00060 #if LASS_COMPILER_TYPE == LASS_COMPILER_TYPE_MSVC
00061 # pragma warning(push)
00062 # pragma warning(disable: 4239) // nonstandard extension used : 'argument' : conversion from 'T' to 'T&'
00063 # pragma warning(disable: 4267) // conversion from 'size_t' to 'unsigned int'
00064 # pragma warning(disable: 4996) // This function or variable may be unsafe ...
00065 #endif
00066
00067 namespace lass
00068 {
00069 namespace util
00070 {
00071 namespace impl
00072 {
00073
00074 const unsigned numberOfProcessors()
00075 {
00076 DWORD_PTR processAffinityMask, systemAffinityMask;
00077 LASS_ENFORCE_WINAPI(GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask));
00078
00079
00080
00081
00082
00083 DWORD_PTR test = systemAffinityMask;
00084 while (test)
00085 {
00086 if (!(test & 0x1))
00087 {
00088 LASS_THROW("our assumption is wrong!");
00089 }
00090 test >>= 1;
00091 }
00092
00093 return util::countBits(systemAffinityMask);
00094 }
00095
00096
00097
00098
00099 class MutexInternal: NonCopyable
00100 {
00101 public:
00102 MutexInternal():
00103 lockCount_(0)
00104 {
00105 mutex_ = LASS_ENFORCE_WINAPI(::CreateMutex(NULL, FALSE, NULL));
00106
00107 }
00108 ~MutexInternal()
00109 {
00110 LASS_ASSERT(lockCount_ == 0);
00111 const BOOL ret = CloseHandle(mutex_);
00112 LASS_ASSERT(ret != 0);
00113 if (ret == 0)
00114 {
00115 const unsigned lastError = impl::lass_GetLastError();
00116 std::cerr << "[LASS RUN MSG] WARNING: CloseHandle failed in ~MutexInternal(): ("
00117 << lastError << ") " << impl::lass_FormatMessage(lastError) << std::endl;
00118 }
00119 }
00120 void lock()
00121 {
00122 const DWORD ret = WaitForSingleObject(mutex_, INFINITE);
00123 switch ( ret )
00124 {
00125 case WAIT_ABANDONED:
00126
00127 LASS_ASSERT(false);
00128 std::cerr << "[LASS RUN MSG] UNDEFINED BEHAVIOUR WARNING: "
00129 << "WaitForSingleObject returned with WAIT_ABANDONED. "
00130 << "Going to take ownership and continue happily." << std::endl;
00131 break;
00132 case WAIT_OBJECT_0:
00133
00134 break;
00135 case WAIT_FAILED:
00136 {
00137 const unsigned lastError = impl::lass_GetLastError();
00138 LASS_THROW("WaitForSingleObject failed: (" << lastError << ") "
00139 << impl::lass_FormatMessage(lastError));
00140 }
00141 case WAIT_TIMEOUT:
00142 default:
00143 LASS_THROW("impossible return value of WaitForSingleObject: " << ret);
00144 }
00145 ++lockCount_;
00146 }
00147 const LockResult tryLock()
00148 {
00149 const DWORD ret = WaitForSingleObject(mutex_, 0);
00150 switch ( ret )
00151 {
00152 case WAIT_ABANDONED:
00153
00154 LASS_ASSERT(false);
00155 std::cerr << "[LASS RUN MSG] UNDEFINED BEHAVIOUR WARNING: "
00156 << "WaitForSingleObject returned with WAIT_ABANDONED. "
00157 << "Going to take ownership and continue happily." << std::endl;
00158 break;
00159 case WAIT_OBJECT_0:
00160
00161 break;
00162 case WAIT_FAILED:
00163 {
00164 const unsigned lastError = impl::lass_GetLastError();
00165 LASS_THROW("WaitForSingleObject failed: (" << lastError << ") "
00166 << impl::lass_FormatMessage(lastError));
00167 }
00168 case WAIT_TIMEOUT:
00169 return lockBusy;
00170 default:
00171 LASS_THROW("impossible return value of WaitForSingleObject: " << ret);
00172 }
00173 ++lockCount_;
00174 return lockSuccess;
00175 }
00176 void unlock()
00177 {
00178 LASS_ASSERT(lockCount_ > 0);
00179 if (lockCount_ == 0)
00180 {
00181 LASS_THROW("attempting to unlock an unlocked mutex");
00182 }
00183 --lockCount_;
00184 LASS_ENFORCE_WINAPI(ReleaseMutex(mutex_));
00185 }
00186 const unsigned lockCount() const
00187 {
00188 return lockCount_;
00189 }
00190 private:
00191 HANDLE mutex_;
00192 unsigned lockCount_;
00193 };
00194
00195
00196
00197
00198
00199
00200 class CriticalSectionInternal: NonCopyable
00201 {
00202 public:
00203 CriticalSectionInternal()
00204 {
00205 InitializeCriticalSection(&criticalSection_);
00206 }
00207 ~CriticalSectionInternal()
00208 {
00209 LASS_ASSERT(criticalSection_.LockCount == -1);
00210 DeleteCriticalSection(&criticalSection_);
00211 }
00212 void lock()
00213 {
00214 EnterCriticalSection(&criticalSection_);
00215 }
00216 const LockResult tryLock()
00217 {
00218 return TryEnterCriticalSection(&criticalSection_) ? lockSuccess : lockBusy;
00219 }
00220 void unlock()
00221 {
00222 LASS_ASSERT(criticalSection_.RecursionCount > 0);
00223 LeaveCriticalSection(&criticalSection_);
00224 }
00225 const unsigned lockCount() const
00226 {
00227 return criticalSection_.RecursionCount;
00228 }
00229 private:
00230 CRITICAL_SECTION criticalSection_;
00231 };
00232
00233
00234
00235
00236
00237
00238 class ConditionInternal: NonCopyable
00239 {
00240 public:
00241 ConditionInternal():
00242 threadsWaiting_(0)
00243 {
00244 event_ = LASS_ENFORCE_WINAPI(::CreateEvent(
00245 NULL,
00246 FALSE,
00247 FALSE,
00248 NULL
00249 ));
00250 }
00251 ~ConditionInternal()
00252 {
00253 const BOOL ret = CloseHandle(event_);
00254 LASS_ASSERT(ret != 0);
00255 if (ret == 0)
00256 {
00257 const unsigned lastError = impl::lass_GetLastError();
00258 std::cerr << "[LASS RUN MSG] UNDEFINED BEHAVIOUR WARNING: "
00259 << " CloseHandle failed in ~MutexInternal(): ("
00260 << lastError << ") " << impl::lass_FormatMessage(lastError) << std::endl;
00261 }
00262 }
00263 void wait()
00264 {
00265 wait(INFINITE);
00266 }
00267 const WaitResult wait(unsigned long iMilliSeconds)
00268 {
00269
00270
00271
00272 ::InterlockedIncrement(&threadsWaiting_);
00273
00274
00275 const DWORD ret = WaitForSingleObject(event_, iMilliSeconds);
00276 ::InterlockedDecrement(&threadsWaiting_);
00277
00278 switch ( ret )
00279 {
00280 case WAIT_OBJECT_0:
00281 return waitSuccess;
00282 case WAIT_TIMEOUT:
00283 return waitTimeout;
00284 case WAIT_FAILED:
00285 {
00286 const unsigned lastError = impl::lass_GetLastError();
00287 LASS_THROW("WaitForSingleObject failed: (" << lastError << ") "
00288 << impl::lass_FormatMessage(lastError));
00289 }
00290 default:
00291 LASS_THROW("impossible return value of WaitForSingleObject: " << ret);
00292 }
00293 }
00294 void signal()
00295 {
00296
00297
00298
00299
00300
00301 LASS_ENFORCE_WINAPI(::SetEvent(event_));
00302 }
00303 void broadcast()
00304 {
00305
00306
00307
00308 LONG nWaiters = threadsWaiting_;
00309
00310
00311
00312
00313 for ( LONG n = 0; n < nWaiters; ++n )
00314 signal();
00315 }
00316 private:
00317 HANDLE event_;
00318 LONG threadsWaiting_;
00319 };
00320
00321
00322
00323
00324
00325
00326 class ThreadLocalStorageInternal: NonCopyable
00327 {
00328 public:
00329 typedef void (*TDestructor)(void*);
00330
00331 ThreadLocalStorageInternal(void (*destructor)(void*))
00332 {
00333 index_ = TlsAlloc();
00334 if (index_ == TLS_OUT_OF_INDEXES)
00335 {
00336 const unsigned lastError = impl::lass_GetLastError();
00337 LASS_THROW("Failed to allocate thread local storage: TlsAlloc failed: ("
00338 << lastError << ") " << impl::lass_FormatMessage(lastError));
00339 }
00340 if (TDestructors* destrs = destructors())
00341 {
00342 try
00343 {
00344 (*destrs)[index_] = destructor;
00345 }
00346 catch (...)
00347 {
00348 freeSlot(index_);
00349 throw;
00350 }
00351 }
00352 else
00353 {
00354 freeSlot(index_);
00355 LASS_THROW("Failed to allocate thread local storage: dead destructor singleton");
00356 }
00357 }
00358 ~ThreadLocalStorageInternal()
00359 {
00360 if (TDestructors* destrs = destructors())
00361 {
00362 destrs->erase(index_);
00363 }
00364 freeSlot(index_);
00365 }
00366 void* const get() const
00367 {
00368 void* result = TlsGetValue(index_);
00369 if (result == 0)
00370 {
00371
00372
00373
00374 return LASS_ENFORCE_WINAPI(result)("Failed to get thread local storage value");
00375 }
00376 return result;
00377 }
00378 void set(void* value)
00379 {
00380 LASS_ENFORCE_WINAPI(TlsSetValue(index_, value))("Failed to set thread local storage value");
00381 }
00382
00383
00384
00385
00386 static void destructLocals()
00387 {
00388 if (TDestructors* destrs = destructors())
00389 {
00390 for (TDestructors::iterator i = destrs->begin(); i != destrs->end(); ++i)
00391 {
00392 DWORD index = i->first;
00393 TDestructor destructor = i->second;
00394 if (destructor)
00395 {
00396 if (void* p = TlsGetValue(index))
00397 {
00398 destructor(p);
00399 TlsSetValue(index, 0);
00400 }
00401 }
00402 }
00403 }
00404 }
00405
00406 private:
00407
00408 typedef std::map<DWORD, TDestructor> TDestructors;
00409
00410 void freeSlot(DWORD index)
00411 {
00412 if (!TlsFree(index))
00413 {
00414 const unsigned lastError = impl::lass_GetLastError();
00415 std::cerr << "[LASS RUN MSG] UNDEFINED BEHAVIOUR WARNING: TlsFree failed: ("
00416 << lastError << ") " << impl::lass_FormatMessage(lastError) << std::endl;
00417 }
00418 }
00419
00420 static TDestructors* destructors()
00421 {
00422 return Singleton<TDestructors, destructionPriorityInternalTlsDestructors>::instance();
00423 }
00424
00425 DWORD index_;
00426 };
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436 class MainLocalStorageDestroyer: NonCopyable
00437 {
00438 public:
00439 ~MainLocalStorageDestroyer()
00440 {
00441 ThreadLocalStorageInternal::destructLocals();
00442 }
00443 private:
00444 static MainLocalStorageDestroyer* forceIntoExistance;
00445 };
00446
00447 MainLocalStorageDestroyer* MainLocalStorageDestroyer::forceIntoExistance =
00448 Singleton<MainLocalStorageDestroyer, destructionPriorityInternalTlsLocalsMain>::instance();
00449
00450
00451
00452
00453
00454
00455 void bindThread(HANDLE thread, unsigned processor)
00456 {
00457 DWORD_PTR affinityMask = 0;
00458 if (processor == Thread::anyProcessor)
00459 {
00460 DWORD_PTR processAffinityMask, systemAffinityMask;
00461 LASS_ENFORCE_WINAPI(GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask));
00462 affinityMask = systemAffinityMask;
00463 }
00464 else
00465 {
00466 if (processor >= util::numberOfProcessors)
00467 {
00468 LASS_THROW("'" << processor << "' is an invalid processor index. "
00469 << "Valid range is [0, " << util::numberOfProcessors << ").");
00470 }
00471 affinityMask = DWORD_PTR(1) << processor;
00472 }
00473 LASS_ENFORCE_WINAPI(SetThreadAffinityMask(thread, affinityMask))
00474 ("Failed to bind thread to processor ")(processor);
00475 }
00476
00477 void setThreadName(DWORD threadId, const char* threadName)
00478 {
00479 char buffer[10];
00480 strncpy(buffer, threadName, 10);
00481 buffer[9] = '\0';
00482
00483 struct THREADNAME_INFO
00484 {
00485 DWORD dwType;
00486 LPCSTR szName;
00487 DWORD dwThreadID;
00488 DWORD dwFlags;
00489 };
00490
00491 THREADNAME_INFO info;
00492 info.dwType = 0x1000;
00493 info.szName = threadName;
00494 info.dwThreadID = threadId;
00495 info.dwFlags = 0;
00496
00497 __try
00498 {
00499 RaiseException(0x406D1388, 0, sizeof(info)/sizeof(DWORD), (ULONG_PTR*)&info);
00500 }
00501 __except(EXCEPTION_CONTINUE_EXECUTION)
00502 {
00503 }
00504 }
00505
00506
00507
00508 #define LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(exception_type)\
00509 catch (const exception_type& error)\
00510 {\
00511 pimpl->error_.reset(new experimental::RemoteExceptionWrapper<exception_type>(error));\
00512 }
00513
00514
00515
00516
00517 class ThreadInternal: NonCopyable
00518 {
00519 public:
00520
00521 ThreadInternal(Thread& iThread, ThreadKind iKind, const char* name):
00522 thread_(iThread),
00523 name_(name),
00524 isJoinable_(iKind == threadJoinable),
00525 isCreated_(false)
00526 {
00527 }
00528
00529 ~ThreadInternal()
00530 {
00531 }
00532
00533
00534
00535 void run()
00536 {
00537 if (isCreated_)
00538 {
00539 LASS_THROW("You can run a thread only once");
00540 }
00541 handle_ = (HANDLE) _beginthreadex(NULL, 0, &ThreadInternal::startThread, this, 0, &id_);
00542 if (handle_ == 0)
00543 {
00544 const int errnum = lass_errno();
00545 LASS_THROW("_beginthreadex failed: (" << errnum << ") " << lass_strerror(errnum));
00546 }
00547 if (name_)
00548 {
00549 setThreadName(id_, name_);
00550 }
00551 runCondition_.wait();
00552 }
00553
00554 void join()
00555 {
00556 if (!(isJoinable_ && isCreated_))
00557 {
00558 LASS_THROW("Can not wait for uncreated or detached threads");
00559 }
00560 else
00561 {
00562 const DWORD ret = WaitForSingleObject(handle_, INFINITE);
00563 switch ( ret )
00564 {
00565 case WAIT_OBJECT_0:
00566
00567 break;
00568 case WAIT_FAILED:
00569 {
00570 const unsigned lastError = impl::lass_GetLastError();
00571 LASS_THROW("WaitForSingleObject failed: (" << lastError << ") "
00572 << impl::lass_FormatMessage(lastError));
00573 }
00574 default:
00575 LASS_THROW("impossible return value of WaitForSingleObject: " << ret);
00576 }
00577 isJoinable_ = false;
00578 if (error_.get())
00579 {
00580 error_->throwSelf();
00581 }
00582 }
00583 }
00584
00585 void bind(unsigned processor)
00586 {
00587 bindThread(handle_, processor);
00588 }
00589
00590 static void sleep(unsigned long iMilliSeconds)
00591 {
00592 Sleep(iMilliSeconds);
00593 }
00594
00595 static void yield()
00596 {
00597 Sleep(0);
00598 }
00599
00600 static void bindCurrent(unsigned processor)
00601 {
00602 bindThread(GetCurrentThread(), processor);
00603 }
00604
00605
00606 static unsigned __stdcall startThread(void* iPimpl)
00607 {
00608 LASS_ASSERT(iPimpl);
00609 ThreadInternal* pimpl = static_cast<ThreadInternal*>(iPimpl);
00610 pimpl->isCreated_ = true;
00611 if (pimpl->isJoinable_)
00612 {
00613 try
00614 {
00615 pimpl->runCondition_.signal();
00616 pimpl->thread_.doRun();
00617 }
00618 catch (const experimental::RemoteExceptionBase& error)
00619 {
00620 pimpl->error_ = error.clone();
00621 }
00622 LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::domain_error)
00623 LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::invalid_argument)
00624 LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::length_error)
00625 LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::out_of_range)
00626 LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::range_error)
00627 LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::overflow_error)
00628 LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::underflow_error)
00629 LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::runtime_error)
00630 LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::logic_error)
00631 LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::exception)
00632 }
00633 else
00634 {
00635 pimpl->runCondition_.signal();
00636 pimpl->thread_.doRun();
00637 delete &pimpl->thread_;
00638 }
00639 return 0;
00640 }
00641
00642 static void onThreadDetach()
00643 {
00644 ThreadLocalStorageInternal::destructLocals();
00645 }
00646
00647 private:
00648
00649 Thread& thread_;
00650 HANDLE handle_;
00651 std::auto_ptr<experimental::RemoteExceptionBase> error_;
00652 Condition runCondition_;
00653 const char* name_;
00654 unsigned id_;
00655 bool isJoinable_;
00656 bool isCreated_;
00657 };
00658
00659
00660 }
00661 }
00662 }
00663
00664 #if LASS_COMPILER_TYPE == LASS_COMPILER_TYPE_MSVC
00665 # pragma warning(pop)
00666 #endif
00667
00668 #ifdef LASS_BUILD_DLL
00669
00670 #include "../dll/dll_main.h"
00671
00672 namespace lass
00673 {
00674 namespace util
00675 {
00676 namespace impl
00677 {
00678
00679 BOOL threadDllMain(HINSTANCE, DWORD dwReason, LPVOID)
00680 {
00681 switch (dwReason)
00682 {
00683 case DLL_PROCESS_DETACH:
00684 case DLL_THREAD_DETACH:
00685 lass::util::impl::ThreadInternal::onThreadDetach();
00686 break;
00687 }
00688 return TRUE;
00689 }
00690 }
00691 }
00692 }
00693
00694 LASS_EXECUTE_BEFORE_MAIN_EX(
00695 lassUtilImplThreadWin32RegisterDllMain,
00696 ::lass::dll::registerDllMain(::lass::util::impl::threadDllMain);
00697 )
00698
00699 #else
00700
00701 namespace
00702 {
00703
00704 void NTAPI lassOnThreadCallback(PVOID, DWORD dwReason, PVOID)
00705 {
00706 if(dwReason == DLL_THREAD_DETACH)
00707 {
00708 lass::util::impl::ThreadInternal::onThreadDetach();
00709 }
00710 }
00711
00712 #if _MSC_VER >= 1400 // VC8.0
00713 # pragma section(".CRT$XLB", read)
00714 #else
00715 # pragma section(".CRT$XLB", read, write)
00716 #endif
00717
00718 extern "C" __declspec(allocate(".CRT$XLB")) PIMAGE_TLS_CALLBACK lassThreadCallback = lassOnThreadCallback;
00719
00720 }
00721
00722 #ifdef _WIN64
00723 # pragma comment(linker, "/INCLUDE:_tls_used")
00724 #else
00725 # pragma comment(linker, "/INCLUDE:__tls_used")
00726 #endif
00727
00728 #endif
00729
00730
00731
00732 #endif
00733
00734
00735