Mutex.h 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  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/HashMap.h>
  10. #include <AK/Types.h>
  11. #include <Kernel/Forward.h>
  12. #include <Kernel/Locking/LockLocation.h>
  13. #include <Kernel/Locking/LockMode.h>
  14. #include <Kernel/WaitQueue.h>
  15. namespace Kernel {
  16. class Mutex {
  17. friend class Thread;
  18. AK_MAKE_NONCOPYABLE(Mutex);
  19. AK_MAKE_NONMOVABLE(Mutex);
  20. public:
  21. using Mode = LockMode;
  22. Mutex(StringView name = {})
  23. : m_name(name)
  24. {
  25. }
  26. ~Mutex() = default;
  27. void lock(Mode mode = Mode::Exclusive, LockLocation const& location = LockLocation::current());
  28. void restore_lock(Mode, u32, LockLocation const& location = LockLocation::current());
  29. void unlock();
  30. [[nodiscard]] Mode force_unlock_if_locked(u32&);
  31. [[nodiscard]] bool is_locked() const
  32. {
  33. SpinlockLocker lock(m_lock);
  34. return m_mode != Mode::Unlocked;
  35. }
  36. [[nodiscard]] bool is_locked_by_current_thread() const
  37. {
  38. SpinlockLocker lock(m_lock);
  39. if (m_mode == Mode::Exclusive)
  40. return m_holder == Thread::current();
  41. if (m_mode == Mode::Shared)
  42. return m_shared_holders.contains(Thread::current());
  43. return false;
  44. }
  45. [[nodiscard]] StringView name() const { return m_name; }
  46. static StringView mode_to_string(Mode mode)
  47. {
  48. switch (mode) {
  49. case Mode::Unlocked:
  50. return "unlocked"sv;
  51. case Mode::Exclusive:
  52. return "exclusive"sv;
  53. case Mode::Shared:
  54. return "shared"sv;
  55. default:
  56. return "invalid"sv;
  57. }
  58. }
  59. private:
  60. using BlockedThreadList = IntrusiveList<Thread, RawPtr<Thread>, &Thread::m_blocked_threads_list_node>;
  61. ALWAYS_INLINE BlockedThreadList& thread_list_for_mode(Mode mode)
  62. {
  63. VERIFY(mode == Mode::Exclusive || mode == Mode::Shared);
  64. return mode == Mode::Exclusive ? m_blocked_threads_list_exclusive : m_blocked_threads_list_shared;
  65. }
  66. void block(Thread&, Mode, SpinlockLocker<Spinlock<u8>>&, u32);
  67. void unblock_waiters(Mode);
  68. StringView m_name;
  69. Mode m_mode { Mode::Unlocked };
  70. // When locked exclusively, only the thread already holding the lock can
  71. // lock it again. When locked in shared mode, any thread can do that.
  72. u32 m_times_locked { 0 };
  73. // One of the threads that hold this lock, or nullptr. When locked in shared
  74. // mode, this is stored on best effort basis: nullptr value does *not* mean
  75. // the lock is unlocked, it just means we don't know which threads hold it.
  76. // When locked exclusively, this is always the one thread that holds the
  77. // lock.
  78. RefPtr<Thread> m_holder;
  79. HashMap<Thread*, u32> m_shared_holders;
  80. BlockedThreadList m_blocked_threads_list_exclusive;
  81. BlockedThreadList m_blocked_threads_list_shared;
  82. mutable Spinlock<u8> m_lock;
  83. };
  84. class MutexLocker {
  85. AK_MAKE_NONCOPYABLE(MutexLocker);
  86. public:
  87. ALWAYS_INLINE explicit MutexLocker()
  88. : m_lock(nullptr)
  89. , m_locked(false)
  90. {
  91. }
  92. ALWAYS_INLINE explicit MutexLocker(Mutex& l, Mutex::Mode mode = Mutex::Mode::Exclusive, LockLocation const& location = LockLocation::current())
  93. : m_lock(&l)
  94. {
  95. m_lock->lock(mode, location);
  96. }
  97. ALWAYS_INLINE ~MutexLocker()
  98. {
  99. if (m_locked)
  100. unlock();
  101. }
  102. ALWAYS_INLINE void unlock()
  103. {
  104. VERIFY(m_lock);
  105. VERIFY(m_locked);
  106. m_locked = false;
  107. m_lock->unlock();
  108. }
  109. ALWAYS_INLINE void attach_and_lock(Mutex& lock, Mutex::Mode mode = Mutex::Mode::Exclusive, LockLocation const& location = LockLocation::current())
  110. {
  111. VERIFY(!m_locked);
  112. m_lock = &lock;
  113. m_locked = true;
  114. m_lock->lock(mode, location);
  115. }
  116. ALWAYS_INLINE void lock(Mutex::Mode mode = Mutex::Mode::Exclusive, LockLocation const& location = LockLocation::current())
  117. {
  118. VERIFY(m_lock);
  119. VERIFY(!m_locked);
  120. m_locked = true;
  121. m_lock->lock(mode, location);
  122. }
  123. private:
  124. Mutex* m_lock;
  125. bool m_locked { true };
  126. };
  127. }