Mutex.cpp 15 KB

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