Lock.cpp 15 KB

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