ThreadPosix.cpp 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  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. #include <AnKi/Util/Thread.h>
  6. #include <AnKi/Util/Logger.h>
  7. #include <AnKi/Util/String.h>
  8. namespace anki {
  9. void Thread::start(void* userData, ThreadCallback callback, const ThreadCoreAffinityMask& coreAffintyMask)
  10. {
  11. ANKI_ASSERT(!m_started);
  12. ANKI_ASSERT(callback != nullptr);
  13. m_callback = callback;
  14. m_userData = userData;
  15. #if ANKI_EXTRA_CHECKS
  16. m_started = true;
  17. #endif
  18. pthread_attr_t attr;
  19. pthread_attr_init(&attr);
  20. auto pthreadCallback = [](void* ud) -> void* {
  21. ANKI_ASSERT(ud != nullptr);
  22. Thread* thread = static_cast<Thread*>(ud);
  23. // Set thread name
  24. setCurrentThreadName(&thread->m_name[0]);
  25. // Call the callback
  26. ThreadCallbackInfo info;
  27. info.m_userData = thread->m_userData;
  28. info.m_threadName = &thread->m_name[0];
  29. const Error err = thread->m_callback(info);
  30. return numberToPtr<void*>(err._getCode());
  31. };
  32. if(pthread_create(&m_handle, &attr, pthreadCallback, this)) [[unlikely]]
  33. {
  34. ANKI_UTIL_LOGF("pthread_create() failed");
  35. }
  36. pthread_attr_destroy(&attr);
  37. if(coreAffintyMask.getSetBitCount())
  38. {
  39. pinToCores(coreAffintyMask);
  40. }
  41. }
  42. Error Thread::join()
  43. {
  44. void* out;
  45. if(pthread_join(m_handle, &out)) [[unlikely]]
  46. {
  47. ANKI_UTIL_LOGF("pthread_join() failed");
  48. }
  49. #if ANKI_EXTRA_CHECKS
  50. m_started = false;
  51. #endif
  52. // Set return error code
  53. return Error(I32(ptrToNumber(out)));
  54. }
  55. void Thread::pinToCores(const ThreadCoreAffinityMask& coreAffintyMask)
  56. {
  57. ANKI_ASSERT(m_started);
  58. cpu_set_t cpus;
  59. CPU_ZERO(&cpus);
  60. ThreadCoreAffinityMask affinity = coreAffintyMask;
  61. while(affinity.getSetBitCount() > 0)
  62. {
  63. const U32 msb = affinity.getMostSignificantBit();
  64. ANKI_ASSERT(msb != kMaxU32);
  65. affinity.unset(msb);
  66. CPU_SET(msb, &cpus);
  67. }
  68. #if ANKI_OS_ANDROID
  69. if(sched_setaffinity(pthread_gettid_np(m_handle), sizeof(cpu_set_t), &cpus))
  70. #else
  71. if(pthread_setaffinity_np(m_handle, sizeof(cpu_set_t), &cpus))
  72. #endif
  73. {
  74. ANKI_UTIL_LOGF("pthread_setaffinity_np() failed");
  75. }
  76. }
  77. void Thread::setCurrentThreadName(const Char* name)
  78. {
  79. // Copy the string first and limit its size
  80. const PtrSize len = min<PtrSize>(strlen(name), kThreadNameMaxLength);
  81. if(len > 0)
  82. {
  83. memcpy(&m_nameTls[0], name, len);
  84. m_nameTls[len] = '\0';
  85. }
  86. else
  87. {
  88. memcpy(&m_nameTls[0], kDefaultThreadName, strlen(kDefaultThreadName) + 1);
  89. }
  90. pthread_setname_np(pthread_self(), &m_nameTls[0]);
  91. }
  92. } // end namespace anki