Mutex.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <Kernel/Debug.h>
  7. #include <Kernel/KSyms.h>
  8. #include <Kernel/Locking/LockLocation.h>
  9. #include <Kernel/Locking/Mutex.h>
  10. #include <Kernel/Locking/Spinlock.h>
  11. #include <Kernel/Thread.h>
  12. namespace Kernel {
  13. void Mutex::lock(Mode mode, [[maybe_unused]] LockLocation const& location)
  14. {
  15. // NOTE: This may be called from an interrupt handler (not an IRQ handler)
  16. // and also from within critical sections!
  17. VERIFY(!Processor::current_in_irq());
  18. if constexpr (LOCK_IN_CRITICAL_DEBUG)
  19. VERIFY_INTERRUPTS_ENABLED();
  20. VERIFY(mode != Mode::Unlocked);
  21. auto current_thread = Thread::current();
  22. SpinlockLocker lock(m_lock);
  23. bool did_block = false;
  24. Mode current_mode = m_mode;
  25. switch (current_mode) {
  26. case Mode::Unlocked: {
  27. dbgln_if(LOCK_TRACE_DEBUG, "Mutex::lock @ ({}) {}: acquire {}, currently unlocked", this, m_name, mode_to_string(mode));
  28. m_mode = mode;
  29. VERIFY(!m_holder);
  30. VERIFY(m_shared_holders.is_empty());
  31. if (mode == Mode::Exclusive) {
  32. m_holder = current_thread;
  33. } else {
  34. VERIFY(mode == Mode::Shared);
  35. m_shared_holders.set(current_thread, 1);
  36. }
  37. VERIFY(m_times_locked == 0);
  38. m_times_locked++;
  39. #if LOCK_DEBUG
  40. if (current_thread) {
  41. current_thread->holding_lock(*this, 1, location);
  42. }
  43. #endif
  44. return;
  45. }
  46. case Mode::Exclusive: {
  47. VERIFY(m_holder);
  48. if (m_holder != current_thread) {
  49. block(*current_thread, mode, lock, 1);
  50. did_block = true;
  51. // If we blocked then m_mode should have been updated to what we requested
  52. VERIFY(m_mode == mode);
  53. }
  54. if (m_mode == Mode::Exclusive) {
  55. VERIFY(m_holder == current_thread);
  56. VERIFY(m_shared_holders.is_empty());
  57. } else if (did_block && mode == Mode::Shared) {
  58. // Only if we blocked trying to acquire a shared lock the lock would have been converted
  59. VERIFY(!m_holder);
  60. VERIFY(!m_shared_holders.is_empty());
  61. VERIFY(m_shared_holders.find(current_thread) != m_shared_holders.end());
  62. }
  63. if constexpr (LOCK_TRACE_DEBUG) {
  64. if (mode == Mode::Exclusive)
  65. dbgln("Mutex::lock @ {} ({}): acquire {}, currently exclusive, holding: {}", this, m_name, mode_to_string(mode), m_times_locked);
  66. else
  67. dbgln("Mutex::lock @ {} ({}): acquire exclusive (requested {}), currently exclusive, holding: {}", this, m_name, mode_to_string(mode), m_times_locked);
  68. }
  69. VERIFY(m_times_locked > 0);
  70. if (!did_block) {
  71. // if we didn't block we must still be an exclusive lock
  72. VERIFY(m_mode == Mode::Exclusive);
  73. m_times_locked++;
  74. }
  75. #if LOCK_DEBUG
  76. current_thread->holding_lock(*this, 1, location);
  77. #endif
  78. return;
  79. }
  80. case Mode::Shared: {
  81. VERIFY(!m_holder);
  82. if (mode == Mode::Exclusive) {
  83. if (m_shared_holders.size() == 1) {
  84. auto it = m_shared_holders.begin();
  85. if (it->key == current_thread) {
  86. it->value++;
  87. m_times_locked++;
  88. m_mode = Mode::Exclusive;
  89. m_holder = current_thread;
  90. m_shared_holders.clear();
  91. dbgln_if(LOCK_TRACE_DEBUG, "Mutex::lock @ {} ({}): acquire {}, converted shared to exclusive lock, locks held {}", this, m_name, mode_to_string(mode), m_times_locked);
  92. return;
  93. }
  94. }
  95. block(*current_thread, mode, lock, 1);
  96. did_block = true;
  97. VERIFY(m_mode == mode);
  98. }
  99. dbgln_if(LOCK_TRACE_DEBUG, "Mutex::lock @ {} ({}): acquire {}, currently shared, locks held {}", this, m_name, mode_to_string(mode), m_times_locked);
  100. VERIFY(m_times_locked > 0);
  101. if (m_mode == Mode::Shared) {
  102. VERIFY(!m_holder);
  103. VERIFY(!did_block || m_shared_holders.contains(current_thread));
  104. } else if (did_block) {
  105. VERIFY(mode == Mode::Exclusive);
  106. VERIFY(m_holder == current_thread);
  107. VERIFY(m_shared_holders.is_empty());
  108. }
  109. if (!did_block) {
  110. // if we didn't block we must still be a shared lock
  111. VERIFY(m_mode == Mode::Shared);
  112. m_times_locked++;
  113. VERIFY(!m_shared_holders.is_empty());
  114. auto it = m_shared_holders.find(current_thread);
  115. if (it != m_shared_holders.end())
  116. it->value++;
  117. else
  118. m_shared_holders.set(current_thread, 1);
  119. }
  120. #if LOCK_DEBUG
  121. current_thread->holding_lock(*this, 1, location);
  122. #endif
  123. return;
  124. }
  125. default:
  126. VERIFY_NOT_REACHED();
  127. }
  128. }
  129. void Mutex::unlock()
  130. {
  131. // NOTE: This may be called from an interrupt handler (not an IRQ handler)
  132. // and also from within critical sections!
  133. if constexpr (LOCK_IN_CRITICAL_DEBUG)
  134. VERIFY_INTERRUPTS_ENABLED();
  135. VERIFY(!Processor::current_in_irq());
  136. auto current_thread = Thread::current();
  137. SpinlockLocker lock(m_lock);
  138. Mode current_mode = m_mode;
  139. if constexpr (LOCK_TRACE_DEBUG) {
  140. if (current_mode == Mode::Shared)
  141. dbgln("Mutex::unlock @ {} ({}): release {}, locks held: {}", this, m_name, mode_to_string(current_mode), m_times_locked);
  142. else
  143. dbgln("Mutex::unlock @ {} ({}): release {}, holding: {}", this, m_name, mode_to_string(current_mode), m_times_locked);
  144. }
  145. VERIFY(current_mode != Mode::Unlocked);
  146. VERIFY(m_times_locked > 0);
  147. m_times_locked--;
  148. switch (current_mode) {
  149. case Mode::Exclusive:
  150. VERIFY(m_holder == current_thread);
  151. VERIFY(m_shared_holders.is_empty());
  152. if (m_times_locked == 0)
  153. m_holder = nullptr;
  154. break;
  155. case Mode::Shared: {
  156. VERIFY(!m_holder);
  157. auto it = m_shared_holders.find(current_thread);
  158. VERIFY(it != m_shared_holders.end());
  159. if (it->value > 1) {
  160. it->value--;
  161. } else {
  162. VERIFY(it->value > 0);
  163. m_shared_holders.remove(it);
  164. }
  165. break;
  166. }
  167. default:
  168. VERIFY_NOT_REACHED();
  169. }
  170. #if LOCK_DEBUG
  171. if (current_thread) {
  172. current_thread->holding_lock(*this, -1, {});
  173. }
  174. #endif
  175. if (m_times_locked == 0) {
  176. VERIFY(current_mode == Mode::Exclusive ? !m_holder : m_shared_holders.is_empty());
  177. m_mode = Mode::Unlocked;
  178. unblock_waiters(current_mode);
  179. }
  180. }
  181. void Mutex::block(Thread& current_thread, Mode mode, SpinlockLocker<Spinlock<u8>>& lock, u32 requested_locks)
  182. {
  183. if constexpr (LOCK_IN_CRITICAL_DEBUG)
  184. VERIFY_INTERRUPTS_ENABLED();
  185. auto& blocked_thread_list = thread_list_for_mode(mode);
  186. VERIFY(!blocked_thread_list.contains(current_thread));
  187. blocked_thread_list.append(current_thread);
  188. dbgln_if(LOCK_TRACE_DEBUG, "Mutex::lock @ {} ({}) waiting...", this, m_name);
  189. current_thread.block(*this, lock, requested_locks);
  190. dbgln_if(LOCK_TRACE_DEBUG, "Mutex::lock @ {} ({}) waited", this, m_name);
  191. VERIFY(blocked_thread_list.contains(current_thread));
  192. blocked_thread_list.remove(current_thread);
  193. }
  194. void Mutex::unblock_waiters(Mode previous_mode)
  195. {
  196. VERIFY(m_times_locked == 0);
  197. VERIFY(m_mode == Mode::Unlocked);
  198. if (m_blocked_threads_list_exclusive.is_empty() && m_blocked_threads_list_shared.is_empty())
  199. return;
  200. auto unblock_shared = [&]() {
  201. if (m_blocked_threads_list_shared.is_empty())
  202. return false;
  203. m_mode = Mode::Shared;
  204. for (auto& thread : m_blocked_threads_list_shared) {
  205. auto requested_locks = thread.unblock_from_lock(*this);
  206. auto set_result = m_shared_holders.set(&thread, requested_locks);
  207. VERIFY(set_result == AK::HashSetResult::InsertedNewEntry);
  208. m_times_locked += requested_locks;
  209. }
  210. return true;
  211. };
  212. auto unblock_exclusive = [&]() {
  213. if (auto* next_exclusive_thread = m_blocked_threads_list_exclusive.first()) {
  214. m_mode = Mode::Exclusive;
  215. m_times_locked = next_exclusive_thread->unblock_from_lock(*this);
  216. m_holder = next_exclusive_thread;
  217. return true;
  218. }
  219. return false;
  220. };
  221. if (previous_mode == Mode::Exclusive) {
  222. if (!unblock_shared())
  223. unblock_exclusive();
  224. } else {
  225. if (!unblock_exclusive())
  226. unblock_shared();
  227. }
  228. }
  229. auto Mutex::force_unlock_if_locked(u32& lock_count_to_restore) -> Mode
  230. {
  231. // NOTE: This may be called from an interrupt handler (not an IRQ handler)
  232. // and also from within critical sections!
  233. VERIFY(!Processor::current_in_irq());
  234. auto current_thread = Thread::current();
  235. SpinlockLocker lock(m_lock);
  236. auto current_mode = m_mode;
  237. switch (current_mode) {
  238. case Mode::Exclusive: {
  239. if (m_holder != current_thread) {
  240. lock_count_to_restore = 0;
  241. return Mode::Unlocked;
  242. }
  243. dbgln_if(LOCK_RESTORE_DEBUG, "Mutex::force_unlock_if_locked @ {}: unlocking exclusive with lock count: {}", this, m_times_locked);
  244. #if LOCK_DEBUG
  245. m_holder->holding_lock(*this, -(int)m_times_locked, {});
  246. #endif
  247. m_holder = nullptr;
  248. VERIFY(m_times_locked > 0);
  249. lock_count_to_restore = m_times_locked;
  250. m_times_locked = 0;
  251. m_mode = Mode::Unlocked;
  252. unblock_waiters(Mode::Exclusive);
  253. break;
  254. }
  255. case Mode::Shared: {
  256. VERIFY(!m_holder);
  257. auto it = m_shared_holders.find(current_thread);
  258. if (it == m_shared_holders.end()) {
  259. lock_count_to_restore = 0;
  260. return Mode::Unlocked;
  261. }
  262. dbgln_if(LOCK_RESTORE_DEBUG, "Mutex::force_unlock_if_locked @ {}: unlocking exclusive with lock count: {}, total locks: {}",
  263. this, it->value, m_times_locked);
  264. VERIFY(it->value > 0);
  265. lock_count_to_restore = it->value;
  266. VERIFY(lock_count_to_restore > 0);
  267. #if LOCK_DEBUG
  268. m_holder->holding_lock(*this, -(int)lock_count_to_restore, {});
  269. #endif
  270. m_shared_holders.remove(it);
  271. VERIFY(m_times_locked >= lock_count_to_restore);
  272. m_times_locked -= lock_count_to_restore;
  273. if (m_times_locked == 0) {
  274. m_mode = Mode::Unlocked;
  275. unblock_waiters(Mode::Shared);
  276. }
  277. break;
  278. }
  279. case Mode::Unlocked: {
  280. lock_count_to_restore = 0;
  281. break;
  282. }
  283. default:
  284. VERIFY_NOT_REACHED();
  285. }
  286. return current_mode;
  287. }
  288. void Mutex::restore_lock(Mode mode, u32 lock_count, [[maybe_unused]] LockLocation const& location)
  289. {
  290. VERIFY(mode != Mode::Unlocked);
  291. VERIFY(lock_count > 0);
  292. VERIFY(!Processor::current_in_irq());
  293. auto current_thread = Thread::current();
  294. bool did_block = false;
  295. SpinlockLocker lock(m_lock);
  296. switch (mode) {
  297. case Mode::Exclusive: {
  298. auto previous_mode = m_mode;
  299. bool need_to_block = false;
  300. if (m_mode == Mode::Exclusive && m_holder != current_thread)
  301. need_to_block = true;
  302. else if (m_mode == Mode::Shared && (m_shared_holders.size() != 1 || !m_shared_holders.contains(current_thread)))
  303. need_to_block = true;
  304. if (need_to_block) {
  305. block(*current_thread, Mode::Exclusive, lock, lock_count);
  306. did_block = true;
  307. // If we blocked then m_mode should have been updated to what we requested
  308. VERIFY(m_mode == Mode::Exclusive);
  309. }
  310. dbgln_if(LOCK_RESTORE_DEBUG, "Mutex::restore_lock @ {}: restoring {} with lock count {}, was {}", this, mode_to_string(mode), lock_count, mode_to_string(previous_mode));
  311. VERIFY(m_mode != Mode::Shared);
  312. VERIFY(m_shared_holders.is_empty());
  313. if (did_block) {
  314. VERIFY(m_times_locked > 0);
  315. VERIFY(m_holder == current_thread);
  316. } else {
  317. if (m_mode == Mode::Unlocked) {
  318. m_mode = Mode::Exclusive;
  319. VERIFY(m_times_locked == 0);
  320. m_times_locked = lock_count;
  321. VERIFY(!m_holder);
  322. m_holder = current_thread;
  323. } else if (m_mode == Mode::Shared) {
  324. // Upgrade the shared lock to an exclusive lock
  325. VERIFY(!m_holder);
  326. VERIFY(m_shared_holders.size() == 1);
  327. VERIFY(m_shared_holders.contains(current_thread));
  328. m_mode = Mode::Exclusive;
  329. m_holder = current_thread;
  330. m_shared_holders.clear();
  331. } else {
  332. VERIFY(m_mode == Mode::Exclusive);
  333. VERIFY(m_holder == current_thread);
  334. VERIFY(m_times_locked > 0);
  335. m_times_locked += lock_count;
  336. }
  337. }
  338. #if LOCK_DEBUG
  339. m_holder->holding_lock(*this, (int)lock_count, location);
  340. #endif
  341. return;
  342. }
  343. case Mode::Shared: {
  344. auto previous_mode = m_mode;
  345. if (m_mode == Mode::Exclusive && m_holder != current_thread) {
  346. block(*current_thread, Mode::Shared, lock, lock_count);
  347. did_block = true;
  348. // If we blocked then m_mode should have been updated to what we requested
  349. VERIFY(m_mode == Mode::Shared);
  350. }
  351. dbgln_if(LOCK_RESTORE_DEBUG, "Mutex::restore_lock @ {}: restoring {} with lock count {}, was {}",
  352. this, mode_to_string(mode), lock_count, mode_to_string(previous_mode));
  353. VERIFY(!m_holder);
  354. if (did_block) {
  355. VERIFY(m_times_locked > 0);
  356. VERIFY(m_shared_holders.contains(current_thread));
  357. } else {
  358. if (m_mode == Mode::Unlocked) {
  359. m_mode = Mode::Shared;
  360. m_times_locked += lock_count;
  361. auto set_result = m_shared_holders.set(current_thread, lock_count);
  362. // There may be other shared lock holders already, but we should not have an entry yet
  363. VERIFY(set_result == AK::HashSetResult::InsertedNewEntry);
  364. } else if (m_mode == Mode::Shared) {
  365. m_times_locked += lock_count;
  366. if (auto it = m_shared_holders.find(current_thread); it != m_shared_holders.end()) {
  367. it->value += lock_count;
  368. } else {
  369. auto set_result = m_shared_holders.set(current_thread, lock_count);
  370. // There may be other shared lock holders already, but we should not have an entry yet
  371. VERIFY(set_result == AK::HashSetResult::InsertedNewEntry);
  372. }
  373. } else {
  374. VERIFY(m_mode == Mode::Exclusive);
  375. VERIFY(m_holder == current_thread);
  376. m_times_locked += lock_count;
  377. }
  378. }
  379. #if LOCK_DEBUG
  380. m_holder->holding_lock(*this, (int)lock_count, location);
  381. #endif
  382. return;
  383. }
  384. default:
  385. VERIFY_NOT_REACHED();
  386. }
  387. }
  388. }