Lock.h 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/Assertions.h>
  8. #include <AK/Atomic.h>
  9. #include <AK/Types.h>
  10. #ifdef __serenity__
  11. # include <unistd.h>
  12. #else
  13. # include <pthread.h>
  14. #endif
  15. namespace Threading {
  16. class Lock {
  17. public:
  18. Lock() { }
  19. ~Lock() { }
  20. void lock();
  21. void unlock();
  22. private:
  23. #ifdef __serenity__
  24. using ThreadID = int;
  25. ALWAYS_INLINE static ThreadID self()
  26. {
  27. return gettid();
  28. }
  29. #else
  30. using ThreadID = pthread_t;
  31. ALWAYS_INLINE static ThreadID self()
  32. {
  33. return pthread_self();
  34. }
  35. #endif
  36. Atomic<ThreadID> m_holder { 0 };
  37. u32 m_level { 0 };
  38. };
  39. class Locker {
  40. public:
  41. ALWAYS_INLINE explicit Locker(Lock& l)
  42. : m_lock(l)
  43. {
  44. lock();
  45. }
  46. ALWAYS_INLINE ~Locker() { unlock(); }
  47. ALWAYS_INLINE void unlock() { m_lock.unlock(); }
  48. ALWAYS_INLINE void lock() { m_lock.lock(); }
  49. private:
  50. Lock& m_lock;
  51. };
  52. ALWAYS_INLINE void Lock::lock()
  53. {
  54. ThreadID tid = self();
  55. if (m_holder == tid) {
  56. ++m_level;
  57. return;
  58. }
  59. for (;;) {
  60. ThreadID expected = 0;
  61. if (m_holder.compare_exchange_strong(expected, tid, AK::memory_order_acq_rel)) {
  62. m_level = 1;
  63. return;
  64. }
  65. #ifdef __serenity__
  66. donate(expected);
  67. #endif
  68. }
  69. }
  70. inline void Lock::unlock()
  71. {
  72. VERIFY(m_holder == self());
  73. VERIFY(m_level);
  74. if (m_level == 1)
  75. m_holder.store(0, AK::memory_order_release);
  76. else
  77. --m_level;
  78. }
  79. template<typename T>
  80. class Lockable {
  81. public:
  82. Lockable() { }
  83. template<typename... Args>
  84. Lockable(Args&&... args)
  85. : m_resource(forward(args)...)
  86. {
  87. }
  88. Lockable(T&& resource)
  89. : m_resource(move(resource))
  90. {
  91. }
  92. Lock& lock() { return m_lock; }
  93. T& resource() { return m_resource; }
  94. T lock_and_copy()
  95. {
  96. Locker locker(m_lock);
  97. return m_resource;
  98. }
  99. private:
  100. T m_resource;
  101. Lock m_lock;
  102. };
  103. }