Baselib_ReentrantLock.inl.h 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. #pragma once
  2. #include "../Baselib_Lock.h"
  3. #include "../Baselib_StaticAssert.h"
  4. #include "../Baselib_Alignment.h"
  5. #include "../Baselib_Thread.h"
  6. typedef struct Baselib_ReentrantLock
  7. {
  8. Baselib_Lock lock;
  9. Baselib_Thread_Id owner;
  10. int32_t count;
  11. } Baselib_ReentrantLock;
  12. BASELIB_STATIC_ASSERT((BASELIB_ALIGN_OF(Baselib_ReentrantLock) + offsetof(Baselib_ReentrantLock, owner)) % sizeof(Baselib_Thread_Id) == 0, "Baselib_ReentrantLock::owner is not aligned for atomic use");
  13. BASELIB_STATIC_ASSERT((BASELIB_ALIGN_OF(Baselib_ReentrantLock) + offsetof(Baselib_ReentrantLock, count)) % sizeof(int32_t) == 0, "Baselib_ReentrantLock::count is not aligned for atomic use");
  14. BASELIB_INLINE_API Baselib_ReentrantLock Baselib_ReentrantLock_Create(void)
  15. {
  16. Baselib_ReentrantLock lock = {Baselib_Lock_Create(), Baselib_Thread_InvalidId, 0};
  17. return lock;
  18. }
  19. BASELIB_INLINE_API void Baselib_ReentrantLock_CreateInplace(Baselib_ReentrantLock* lockData)
  20. {
  21. Baselib_Lock_CreateInplace(&lockData->lock);
  22. lockData->owner = Baselib_Thread_InvalidId;
  23. lockData->count = 0;
  24. }
  25. COMPILER_WARN_UNUSED_RESULT
  26. BASELIB_INLINE_API bool Baselib_ReentrantLock_TryAcquire(Baselib_ReentrantLock* lock)
  27. {
  28. const Baselib_Thread_Id currentThreadId = Baselib_Thread_GetCurrentThreadId();
  29. const Baselib_Thread_Id lockOwner = Baselib_atomic_load_ptr_relaxed(&lock->owner);
  30. if (OPTIMIZER_LIKELY(currentThreadId != lockOwner))
  31. {
  32. if (!Baselib_Lock_TryAcquire(&lock->lock))
  33. return false;
  34. lock->owner = currentThreadId;
  35. lock->count = 1;
  36. return true;
  37. }
  38. lock->count++;
  39. return true;
  40. }
  41. BASELIB_INLINE_API void Baselib_ReentrantLock_Acquire(Baselib_ReentrantLock* lock)
  42. {
  43. const Baselib_Thread_Id currentThreadId = Baselib_Thread_GetCurrentThreadId();
  44. const Baselib_Thread_Id lockOwner = Baselib_atomic_load_ptr_relaxed(&lock->owner);
  45. if (OPTIMIZER_LIKELY(currentThreadId != lockOwner))
  46. {
  47. Baselib_Lock_Acquire(&lock->lock);
  48. lock->owner = currentThreadId;
  49. lock->count = 1;
  50. return;
  51. }
  52. lock->count++;
  53. }
  54. COMPILER_WARN_UNUSED_RESULT
  55. BASELIB_INLINE_API bool Baselib_ReentrantLock_TryTimedAcquire(Baselib_ReentrantLock* lock, const uint32_t timeoutInMilliseconds)
  56. {
  57. const Baselib_Thread_Id currentThreadId = Baselib_Thread_GetCurrentThreadId();
  58. const Baselib_Thread_Id lockOwner = Baselib_atomic_load_ptr_relaxed(&lock->owner);
  59. if (OPTIMIZER_LIKELY(currentThreadId != lockOwner))
  60. {
  61. if (!Baselib_Lock_TryTimedAcquire(&lock->lock, timeoutInMilliseconds))
  62. return false;
  63. lock->owner = currentThreadId;
  64. lock->count = 1;
  65. return true;
  66. }
  67. lock->count++;
  68. return true;
  69. }
  70. BASELIB_INLINE_API void Baselib_ReentrantLock_Release(Baselib_ReentrantLock* lock)
  71. {
  72. if (lock->count > 0)
  73. {
  74. BaselibAssert(Baselib_atomic_load_ptr_relaxed(&lock->owner) == Baselib_Thread_GetCurrentThreadId(), "A recursive lock can only be unlocked by the locking thread");
  75. if (OPTIMIZER_LIKELY(lock->count == 1))
  76. {
  77. lock->owner = Baselib_Thread_InvalidId;
  78. lock->count = 0;
  79. Baselib_Lock_Release(&lock->lock);
  80. return;
  81. }
  82. lock->count--;
  83. }
  84. }
  85. BASELIB_INLINE_API void Baselib_ReentrantLock_Free(Baselib_ReentrantLock* lock)
  86. {
  87. if (!lock)
  88. return;
  89. Baselib_Lock_Free(&lock->lock);
  90. }
  91. BASELIB_INLINE_API void Baselib_ReentrantLock_FreeInplace(Baselib_ReentrantLock* lock)
  92. {
  93. if (!lock)
  94. return;
  95. Baselib_Lock_FreeInplace(&lock->lock);
  96. }