Semaphore.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  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. #elif defined(JPH_PLATFORM_BLUE)
  44. if (!JPH_PLATFORM_BLUE_SEMAPHORE_INIT(mSemaphore))
  45. {
  46. Trace("Failed to create semaphore");
  47. std::abort();
  48. }
  49. #endif
  50. }
  51. Semaphore::~Semaphore()
  52. {
  53. #ifdef JPH_PLATFORM_WINDOWS
  54. CloseHandle(mSemaphore);
  55. #elif defined(JPH_USE_PTHREADS)
  56. sem_destroy(&mSemaphore);
  57. #elif defined(JPH_USE_GRAND_CENTRAL_DISPATCH)
  58. dispatch_release(mSemaphore);
  59. #elif defined(JPH_PLATFORM_BLUE)
  60. JPH_PLATFORM_BLUE_SEMAPHORE_DESTROY(mSemaphore);
  61. #endif
  62. }
  63. void Semaphore::Release(uint inNumber)
  64. {
  65. JPH_ASSERT(inNumber > 0);
  66. #if defined(JPH_PLATFORM_WINDOWS) || defined(JPH_USE_PTHREADS) || defined(JPH_USE_GRAND_CENTRAL_DISPATCH) || defined(JPH_PLATFORM_BLUE)
  67. int old_value = mCount.fetch_add(inNumber, std::memory_order_release);
  68. if (old_value < 0)
  69. {
  70. int new_value = old_value + (int)inNumber;
  71. int num_to_release = min(new_value, 0) - old_value;
  72. #ifdef JPH_PLATFORM_WINDOWS
  73. ::ReleaseSemaphore(mSemaphore, num_to_release, nullptr);
  74. #elif defined(JPH_USE_PTHREADS)
  75. for (int i = 0; i < num_to_release; ++i)
  76. sem_post(&mSemaphore);
  77. #elif defined(JPH_USE_GRAND_CENTRAL_DISPATCH)
  78. for (int i = 0; i < num_to_release; ++i)
  79. dispatch_semaphore_signal(mSemaphore);
  80. #elif defined(JPH_PLATFORM_BLUE)
  81. JPH_PLATFORM_BLUE_SEMAPHORE_SIGNAL(mSemaphore, num_to_release);
  82. #endif
  83. }
  84. #else
  85. std::lock_guard lock(mLock);
  86. mCount.fetch_add(inNumber, std::memory_order_relaxed);
  87. if (inNumber > 1)
  88. mWaitVariable.notify_all();
  89. else
  90. mWaitVariable.notify_one();
  91. #endif
  92. }
  93. void Semaphore::Acquire(uint inNumber)
  94. {
  95. JPH_ASSERT(inNumber > 0);
  96. #if defined(JPH_PLATFORM_WINDOWS) || defined(JPH_USE_PTHREADS) || defined(JPH_USE_GRAND_CENTRAL_DISPATCH) || defined(JPH_PLATFORM_BLUE)
  97. int old_value = mCount.fetch_sub(inNumber, std::memory_order_acquire);
  98. int new_value = old_value - (int)inNumber;
  99. if (new_value < 0)
  100. {
  101. int num_to_acquire = min(old_value, 0) - new_value;
  102. #ifdef JPH_PLATFORM_WINDOWS
  103. for (int i = 0; i < num_to_acquire; ++i)
  104. WaitForSingleObject(mSemaphore, INFINITE);
  105. #elif defined(JPH_USE_PTHREADS)
  106. for (int i = 0; i < num_to_acquire; ++i)
  107. sem_wait(&mSemaphore);
  108. #elif defined(JPH_USE_GRAND_CENTRAL_DISPATCH)
  109. for (int i = 0; i < num_to_acquire; ++i)
  110. dispatch_semaphore_wait(mSemaphore, DISPATCH_TIME_FOREVER);
  111. #elif defined(JPH_PLATFORM_BLUE)
  112. JPH_PLATFORM_BLUE_SEMAPHORE_WAIT(mSemaphore, num_to_acquire);
  113. #endif
  114. }
  115. #else
  116. std::unique_lock lock(mLock);
  117. mWaitVariable.wait(lock, [this, inNumber]() {
  118. return mCount.load(std::memory_order_relaxed) >= int(inNumber);
  119. });
  120. mCount.fetch_sub(inNumber, std::memory_order_relaxed);
  121. #endif
  122. }
  123. JPH_NAMESPACE_END