Semaphore.cpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2023 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include <Jolt/Jolt.h>
  5. #include <Jolt/Core/Semaphore.h>
  6. #ifdef JPH_PLATFORM_WINDOWS
  7. JPH_SUPPRESS_WARNING_PUSH
  8. JPH_MSVC_SUPPRESS_WARNING(5039) // winbase.h(13179): warning C5039: 'TpSetCallbackCleanupGroup': pointer or reference to potentially throwing function passed to 'extern "C"' function under -EHc. Undefined behavior may occur if this function throws an exception.
  9. #ifndef WIN32_LEAN_AND_MEAN
  10. #define WIN32_LEAN_AND_MEAN
  11. #endif
  12. #ifndef JPH_COMPILER_MINGW
  13. #include <Windows.h>
  14. #else
  15. #include <windows.h>
  16. #endif
  17. JPH_SUPPRESS_WARNING_POP
  18. #endif
  19. JPH_NAMESPACE_BEGIN
  20. Semaphore::Semaphore()
  21. {
  22. #ifdef JPH_PLATFORM_WINDOWS
  23. mSemaphore = CreateSemaphore(nullptr, 0, INT_MAX, nullptr);
  24. if (mSemaphore == nullptr)
  25. {
  26. Trace("Failed to create semaphore");
  27. std::abort();
  28. }
  29. #elif defined(JPH_USE_PTHREADS)
  30. int ret = sem_init(&mSemaphore, 0, 0);
  31. if (ret == -1)
  32. {
  33. Trace("Failed to create semaphore");
  34. std::abort();
  35. }
  36. #elif defined(JPH_USE_GRAND_CENTRAL_DISPATCH)
  37. mSemaphore = dispatch_semaphore_create(0);
  38. if (mSemaphore == nullptr)
  39. {
  40. Trace("Failed to create semaphore");
  41. std::abort();
  42. }
  43. #endif
  44. }
  45. Semaphore::~Semaphore()
  46. {
  47. #ifdef JPH_PLATFORM_WINDOWS
  48. CloseHandle(mSemaphore);
  49. #elif defined(JPH_USE_PTHREADS)
  50. sem_destroy(&mSemaphore);
  51. #elif defined(JPH_USE_GRAND_CENTRAL_DISPATCH)
  52. dispatch_release(mSemaphore);
  53. #endif
  54. }
  55. void Semaphore::Release(uint inNumber)
  56. {
  57. JPH_ASSERT(inNumber > 0);
  58. #if defined(JPH_PLATFORM_WINDOWS) || defined(JPH_USE_PTHREADS) || defined(JPH_USE_GRAND_CENTRAL_DISPATCH)
  59. int old_value = mCount.fetch_add(inNumber, std::memory_order_release);
  60. if (old_value < 0)
  61. {
  62. int new_value = old_value + (int)inNumber;
  63. int num_to_release = min(new_value, 0) - old_value;
  64. #ifdef JPH_PLATFORM_WINDOWS
  65. ::ReleaseSemaphore(mSemaphore, num_to_release, nullptr);
  66. #elif defined(JPH_USE_PTHREADS)
  67. for (int i = 0; i < num_to_release; ++i)
  68. sem_post(&mSemaphore);
  69. #elif defined(JPH_USE_GRAND_CENTRAL_DISPATCH)
  70. for (int i = 0; i < num_to_release; ++i)
  71. dispatch_semaphore_signal(mSemaphore);
  72. #endif
  73. }
  74. #else
  75. std::lock_guard lock(mLock);
  76. mCount.fetch_add(inNumber, std::memory_order_relaxed);
  77. if (inNumber > 1)
  78. mWaitVariable.notify_all();
  79. else
  80. mWaitVariable.notify_one();
  81. #endif
  82. }
  83. void Semaphore::Acquire(uint inNumber)
  84. {
  85. JPH_ASSERT(inNumber > 0);
  86. #if defined(JPH_PLATFORM_WINDOWS) || defined(JPH_USE_PTHREADS) || defined(JPH_USE_GRAND_CENTRAL_DISPATCH)
  87. int old_value = mCount.fetch_sub(inNumber, std::memory_order_acquire);
  88. int new_value = old_value - (int)inNumber;
  89. if (new_value < 0)
  90. {
  91. int num_to_acquire = min(old_value, 0) - new_value;
  92. for (int i = 0; i < num_to_acquire; ++i)
  93. #ifdef JPH_PLATFORM_WINDOWS
  94. WaitForSingleObject(mSemaphore, INFINITE);
  95. #elif defined(JPH_USE_PTHREADS)
  96. sem_wait(&mSemaphore);
  97. #elif defined(JPH_USE_GRAND_CENTRAL_DISPATCH)
  98. dispatch_semaphore_wait(mSemaphore, DISPATCH_TIME_FOREVER);
  99. #endif
  100. }
  101. #else
  102. std::unique_lock lock(mLock);
  103. mWaitVariable.wait(lock, [this, inNumber]() {
  104. return mCount.load(std::memory_order_relaxed) >= int(inNumber);
  105. });
  106. mCount.fetch_sub(inNumber, std::memory_order_relaxed);
  107. #endif
  108. }
  109. JPH_NAMESPACE_END