ThreadWindows.cpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. // Add support for condition variables
  6. #define _WIN32_WINNT _WIN32_WINNT_VISTA
  7. #include <AnKi/Util/Thread.h>
  8. #include <AnKi/Util/Logger.h>
  9. namespace anki {
  10. DWORD ANKI_WINAPI Thread::threadCallback(LPVOID ud)
  11. {
  12. ANKI_ASSERT(ud != nullptr);
  13. Thread* thread = reinterpret_cast<Thread*>(ud);
  14. setCurrentThreadName(&thread->m_name[0]);
  15. // Call the callback
  16. ThreadCallbackInfo info;
  17. info.m_userData = thread->m_userData;
  18. info.m_threadName = &thread->m_name[0];
  19. thread->m_returnCode = thread->m_callback(info);
  20. return thread->m_returnCode._getCode();
  21. }
  22. void Thread::start(void* userData, ThreadCallback callback, const ThreadCoreAffinityMask& coreAffintyMask)
  23. {
  24. ANKI_ASSERT(!m_started);
  25. ANKI_ASSERT(callback != nullptr);
  26. m_callback = callback;
  27. m_userData = userData;
  28. #if ANKI_EXTRA_CHECKS
  29. m_started = true;
  30. #endif
  31. m_returnCode = Error::kNone;
  32. m_handle = CreateThread(nullptr, 0, threadCallback, this, 0, nullptr);
  33. if(m_handle == nullptr)
  34. {
  35. ANKI_UTIL_LOGF("CreateThread() failed");
  36. }
  37. if(coreAffintyMask.getAnySet())
  38. {
  39. pinToCores(coreAffintyMask);
  40. }
  41. }
  42. Error Thread::join()
  43. {
  44. ANKI_ASSERT(m_started);
  45. // Wait thread
  46. WaitForSingleObject(m_handle, INFINITE);
  47. // Delete handle
  48. const BOOL ok = CloseHandle(m_handle);
  49. if(!ok)
  50. {
  51. ANKI_UTIL_LOGF("CloseHandle() failed");
  52. }
  53. m_handle = nullptr;
  54. #if ANKI_EXTRA_CHECKS
  55. m_started = false;
  56. #endif
  57. return m_returnCode;
  58. }
  59. void Thread::pinToCores(const ThreadCoreAffinityMask& coreAffintyMask)
  60. {
  61. static_assert(std::is_same<DWORD_PTR, U64>::value, "See file");
  62. ThreadCoreAffinityMask affinityTest = coreAffintyMask;
  63. DWORD_PTR affinity = 0;
  64. for(DWORD_PTR bit = 0; bit < 64; ++bit)
  65. {
  66. if(coreAffintyMask.get(bit))
  67. {
  68. affinity |= 1ull << bit;
  69. affinityTest.unset(bit);
  70. }
  71. }
  72. if(SetThreadAffinityMask(m_handle, affinity) == 0)
  73. {
  74. ANKI_UTIL_LOGF("SetThreadAffinityMask() failed");
  75. }
  76. if(affinityTest.getSetBitCount() > 0)
  77. {
  78. ANKI_UTIL_LOGE("Couldn't set affinity for all cores. Need to refactor the code");
  79. }
  80. }
  81. void Thread::setCurrentThreadName(const Char* name)
  82. {
  83. // Copy the string first and limit its size
  84. const PtrSize len = min<PtrSize>(strlen(name), kThreadNameMaxLength);
  85. if(len > 0)
  86. {
  87. memcpy(&m_nameTls[0], name, len);
  88. m_nameTls[len] = '\0';
  89. }
  90. else
  91. {
  92. memcpy(&m_nameTls[0], kDefaultThreadName, strlen(kDefaultThreadName) + 1);
  93. }
  94. // Convert to wstring
  95. Array<WChar, kThreadNameMaxLength + 1> wstring;
  96. mbstowcs(&wstring[0], &m_nameTls[0], wstring.getSize());
  97. // Set it
  98. const HRESULT r = SetThreadDescription(GetCurrentThread(), &wstring[0]);
  99. if(r < 0)
  100. {
  101. ANKI_UTIL_LOGE("SetThreadDescription() failed. Ignoring error");
  102. }
  103. }
  104. } // end namespace anki