Lock.h 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. #pragma once
  2. #ifdef __serenity__
  3. #include <AK/Assertions.h>
  4. #include <AK/Types.h>
  5. #include <unistd.h>
  6. #define memory_barrier() asm volatile("" :: \
  7. : "memory")
  8. static inline u32 CAS(volatile u32* mem, u32 newval, u32 oldval)
  9. {
  10. u32 ret;
  11. asm volatile(
  12. "cmpxchgl %2, %1"
  13. : "=a"(ret), "+m"(*mem)
  14. : "r"(newval), "0"(oldval)
  15. : "cc", "memory");
  16. return ret;
  17. }
  18. namespace LibThread {
  19. class Lock {
  20. public:
  21. Lock() {}
  22. ~Lock() {}
  23. void lock();
  24. void unlock();
  25. private:
  26. volatile u32 m_lock { 0 };
  27. u32 m_level { 0 };
  28. int m_holder { -1 };
  29. };
  30. class Locker {
  31. public:
  32. [[gnu::always_inline]] inline explicit Locker(Lock& l)
  33. : m_lock(l)
  34. {
  35. lock();
  36. }
  37. [[gnu::always_inline]] inline ~Locker() { unlock(); }
  38. [[gnu::always_inline]] inline void unlock() { m_lock.unlock(); }
  39. [[gnu::always_inline]] inline void lock() { m_lock.lock(); }
  40. private:
  41. Lock& m_lock;
  42. };
  43. [[gnu::always_inline]] inline void Lock::lock()
  44. {
  45. int tid = gettid();
  46. for (;;) {
  47. if (CAS(&m_lock, 1, 0) == 0) {
  48. if (m_holder == -1 || m_holder == tid) {
  49. m_holder = tid;
  50. ++m_level;
  51. memory_barrier();
  52. m_lock = 0;
  53. return;
  54. }
  55. m_lock = 0;
  56. }
  57. donate(m_holder);
  58. }
  59. }
  60. inline void Lock::unlock()
  61. {
  62. for (;;) {
  63. if (CAS(&m_lock, 1, 0) == 0) {
  64. ASSERT(m_holder == gettid());
  65. ASSERT(m_level);
  66. --m_level;
  67. if (m_level) {
  68. memory_barrier();
  69. m_lock = 0;
  70. return;
  71. }
  72. m_holder = -1;
  73. memory_barrier();
  74. m_lock = 0;
  75. return;
  76. }
  77. donate(m_holder);
  78. }
  79. }
  80. #define LOCKER(lock) LibThread::Locker locker(lock)
  81. template<typename T>
  82. class Lockable {
  83. public:
  84. Lockable() {}
  85. Lockable(T&& resource)
  86. : m_resource(move(resource))
  87. {
  88. }
  89. Lock& lock() { return m_lock; }
  90. T& resource() { return m_resource; }
  91. T lock_and_copy()
  92. {
  93. LOCKER(m_lock);
  94. return m_resource;
  95. }
  96. private:
  97. T m_resource;
  98. Lock m_lock;
  99. };
  100. }
  101. #else
  102. namespace LibThread {
  103. class Lock {
  104. public:
  105. Lock() { }
  106. ~Lock() { }
  107. };
  108. }
  109. #define LOCKER(x)
  110. #endif