Baselib_ReentrantLock.inl.h 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  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. COMPILER_WARN_UNUSED_RESULT
  20. BASELIB_INLINE_API bool Baselib_ReentrantLock_TryAcquire(Baselib_ReentrantLock* lock)
  21. {
  22. const Baselib_Thread_Id currentThreadId = Baselib_Thread_GetCurrentThreadId();
  23. const Baselib_Thread_Id lockOwner = Baselib_atomic_load_ptr_relaxed(&lock->owner);
  24. if (OPTIMIZER_LIKELY(currentThreadId != lockOwner))
  25. {
  26. if (!Baselib_Lock_TryAcquire(&lock->lock))
  27. return false;
  28. lock->owner = currentThreadId;
  29. lock->count = 1;
  30. return true;
  31. }
  32. lock->count++;
  33. return true;
  34. }
  35. BASELIB_INLINE_API void Baselib_ReentrantLock_Acquire(Baselib_ReentrantLock* lock)
  36. {
  37. const Baselib_Thread_Id currentThreadId = Baselib_Thread_GetCurrentThreadId();
  38. const Baselib_Thread_Id lockOwner = Baselib_atomic_load_ptr_relaxed(&lock->owner);
  39. if (OPTIMIZER_LIKELY(currentThreadId != lockOwner))
  40. {
  41. Baselib_Lock_Acquire(&lock->lock);
  42. lock->owner = currentThreadId;
  43. lock->count = 1;
  44. return;
  45. }
  46. lock->count++;
  47. }
  48. COMPILER_WARN_UNUSED_RESULT
  49. BASELIB_INLINE_API bool Baselib_ReentrantLock_TryTimedAcquire(Baselib_ReentrantLock* lock, const uint32_t timeoutInMilliseconds)
  50. {
  51. const Baselib_Thread_Id currentThreadId = Baselib_Thread_GetCurrentThreadId();
  52. const Baselib_Thread_Id lockOwner = Baselib_atomic_load_ptr_relaxed(&lock->owner);
  53. if (OPTIMIZER_LIKELY(currentThreadId != lockOwner))
  54. {
  55. if (!Baselib_Lock_TryTimedAcquire(&lock->lock, timeoutInMilliseconds))
  56. return false;
  57. lock->owner = currentThreadId;
  58. lock->count = 1;
  59. return true;
  60. }
  61. lock->count++;
  62. return true;
  63. }
  64. BASELIB_INLINE_API void Baselib_ReentrantLock_Release(Baselib_ReentrantLock* lock)
  65. {
  66. if (lock->count > 0)
  67. {
  68. BaselibAssert(Baselib_atomic_load_ptr_relaxed(&lock->owner) == Baselib_Thread_GetCurrentThreadId(), "A recursive lock can only be unlocked by the locking thread");
  69. if (OPTIMIZER_LIKELY(lock->count == 1))
  70. {
  71. lock->owner = Baselib_Thread_InvalidId;
  72. lock->count = 0;
  73. Baselib_Lock_Release(&lock->lock);
  74. return;
  75. }
  76. lock->count--;
  77. }
  78. }
  79. BASELIB_INLINE_API void Baselib_ReentrantLock_Free(Baselib_ReentrantLock* lock)
  80. {
  81. if (!lock)
  82. return;
  83. Baselib_Lock_Free(&lock->lock);
  84. }