Semaphore.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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. JPH_MSVC2026_PLUS_SUPPRESS_WARNING(4865) // wingdi.h(2806,1): '<unnamed-enum-DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER>': the underlying type will change from 'int' to '__int64' when '/Zc:enumTypes' is specified on the command line
  10. #ifndef WIN32_LEAN_AND_MEAN
  11. #define WIN32_LEAN_AND_MEAN
  12. #endif
  13. #ifndef JPH_COMPILER_MINGW
  14. #include <Windows.h>
  15. #else
  16. #include <windows.h>
  17. #endif
  18. JPH_SUPPRESS_WARNING_POP
  19. #endif
  20. JPH_NAMESPACE_BEGIN
  21. Semaphore::Semaphore()
  22. {
  23. #ifdef JPH_PLATFORM_WINDOWS
  24. mSemaphore = CreateSemaphore(nullptr, 0, INT_MAX, nullptr);
  25. if (mSemaphore == nullptr)
  26. {
  27. Trace("Failed to create semaphore");
  28. std::abort();
  29. }
  30. #elif defined(JPH_USE_PTHREADS)
  31. int ret = sem_init(&mSemaphore, 0, 0);
  32. if (ret == -1)
  33. {
  34. Trace("Failed to create semaphore");
  35. std::abort();
  36. }
  37. #elif defined(JPH_USE_GRAND_CENTRAL_DISPATCH)
  38. mSemaphore = dispatch_semaphore_create(0);
  39. if (mSemaphore == nullptr)
  40. {
  41. Trace("Failed to create semaphore");
  42. std::abort();
  43. }
  44. #elif defined(JPH_PLATFORM_BLUE)
  45. if (!JPH_PLATFORM_BLUE_SEMAPHORE_INIT(mSemaphore))
  46. {
  47. Trace("Failed to create semaphore");
  48. std::abort();
  49. }
  50. #endif
  51. }
  52. Semaphore::~Semaphore()
  53. {
  54. #ifdef JPH_PLATFORM_WINDOWS
  55. CloseHandle(mSemaphore);
  56. #elif defined(JPH_USE_PTHREADS)
  57. sem_destroy(&mSemaphore);
  58. #elif defined(JPH_USE_GRAND_CENTRAL_DISPATCH)
  59. dispatch_release(mSemaphore);
  60. #elif defined(JPH_PLATFORM_BLUE)
  61. JPH_PLATFORM_BLUE_SEMAPHORE_DESTROY(mSemaphore);
  62. #endif
  63. }
  64. void Semaphore::Release(uint inNumber)
  65. {
  66. JPH_ASSERT(inNumber > 0);
  67. #if defined(JPH_PLATFORM_WINDOWS) || defined(JPH_USE_PTHREADS) || defined(JPH_USE_GRAND_CENTRAL_DISPATCH) || defined(JPH_PLATFORM_BLUE)
  68. int old_value = mCount.fetch_add(inNumber, std::memory_order_release);
  69. if (old_value < 0)
  70. {
  71. int new_value = old_value + (int)inNumber;
  72. int num_to_release = min(new_value, 0) - old_value;
  73. #ifdef JPH_PLATFORM_WINDOWS
  74. ::ReleaseSemaphore(mSemaphore, num_to_release, nullptr);
  75. #elif defined(JPH_USE_PTHREADS)
  76. for (int i = 0; i < num_to_release; ++i)
  77. sem_post(&mSemaphore);
  78. #elif defined(JPH_USE_GRAND_CENTRAL_DISPATCH)
  79. for (int i = 0; i < num_to_release; ++i)
  80. dispatch_semaphore_signal(mSemaphore);
  81. #elif defined(JPH_PLATFORM_BLUE)
  82. JPH_PLATFORM_BLUE_SEMAPHORE_SIGNAL(mSemaphore, num_to_release);
  83. #endif
  84. }
  85. #else
  86. std::lock_guard lock(mLock);
  87. mCount.fetch_add(inNumber, std::memory_order_relaxed);
  88. if (inNumber > 1)
  89. mWaitVariable.notify_all();
  90. else
  91. mWaitVariable.notify_one();
  92. #endif
  93. }
  94. void Semaphore::Acquire(uint inNumber)
  95. {
  96. JPH_ASSERT(inNumber > 0);
  97. #if defined(JPH_PLATFORM_WINDOWS) || defined(JPH_USE_PTHREADS) || defined(JPH_USE_GRAND_CENTRAL_DISPATCH) || defined(JPH_PLATFORM_BLUE)
  98. int old_value = mCount.fetch_sub(inNumber, std::memory_order_acquire);
  99. int new_value = old_value - (int)inNumber;
  100. if (new_value < 0)
  101. {
  102. int num_to_acquire = min(old_value, 0) - new_value;
  103. #ifdef JPH_PLATFORM_WINDOWS
  104. for (int i = 0; i < num_to_acquire; ++i)
  105. WaitForSingleObject(mSemaphore, INFINITE);
  106. #elif defined(JPH_USE_PTHREADS)
  107. for (int i = 0; i < num_to_acquire; ++i)
  108. sem_wait(&mSemaphore);
  109. #elif defined(JPH_USE_GRAND_CENTRAL_DISPATCH)
  110. for (int i = 0; i < num_to_acquire; ++i)
  111. dispatch_semaphore_wait(mSemaphore, DISPATCH_TIME_FOREVER);
  112. #elif defined(JPH_PLATFORM_BLUE)
  113. JPH_PLATFORM_BLUE_SEMAPHORE_WAIT(mSemaphore, num_to_acquire);
  114. #endif
  115. }
  116. #else
  117. std::unique_lock lock(mLock);
  118. mWaitVariable.wait(lock, [this, inNumber]() {
  119. return mCount.load(std::memory_order_relaxed) >= int(inNumber);
  120. });
  121. mCount.fetch_sub(inNumber, std::memory_order_relaxed);
  122. #endif
  123. }
  124. JPH_NAMESPACE_END