Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <Kernel/KSyms.h>
28#include <Kernel/Lock.h>
29#include <Kernel/Thread.h>
30
31namespace Kernel {
32
33void Lock::lock()
34{
35 ASSERT(!Scheduler::is_active());
36 if (!are_interrupts_enabled()) {
37 klog() << "Interrupts disabled when trying to take Lock{" << m_name << "}";
38 dump_backtrace();
39 hang();
40 }
41 for (;;) {
42 bool expected = false;
43 if (m_lock.compare_exchange_strong(expected, true, AK::memory_order_acq_rel)) {
44 if (!m_holder || m_holder == Thread::current) {
45 m_holder = Thread::current;
46 ++m_level;
47 m_lock.store(false, AK::memory_order_release);
48 return;
49 }
50 Thread::current->wait_on(m_queue, &m_lock, m_holder, m_name);
51 }
52 }
53}
54
55void Lock::unlock()
56{
57 for (;;) {
58 bool expected = false;
59 if (m_lock.compare_exchange_strong(expected, true, AK::memory_order_acq_rel)) {
60 ASSERT(m_holder == Thread::current);
61 ASSERT(m_level);
62 --m_level;
63 if (m_level) {
64 m_lock.store(false, AK::memory_order_release);
65 return;
66 }
67 m_holder = nullptr;
68 m_queue.wake_one(&m_lock);
69 return;
70 }
71 // I don't know *who* is using "m_lock", so just yield.
72 Scheduler::yield();
73 }
74}
75
76bool Lock::force_unlock_if_locked()
77{
78 InterruptDisabler disabler;
79 if (m_holder != Thread::current)
80 return false;
81 ASSERT(m_level == 1);
82 ASSERT(m_holder == Thread::current);
83 m_holder = nullptr;
84 --m_level;
85 m_queue.wake_one();
86 return true;
87}
88
89void Lock::clear_waiters()
90{
91 InterruptDisabler disabler;
92 m_queue.clear();
93}
94
95}