summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Kernel/Lock.cpp70
1 files changed, 70 insertions, 0 deletions
diff --git a/Kernel/Lock.cpp b/Kernel/Lock.cpp
new file mode 100644
index 0000000000..bd7e35d719
--- /dev/null
+++ b/Kernel/Lock.cpp
@@ -0,0 +1,70 @@
+#include <Kernel/Lock.h>
+
+void Lock::lock()
+{
+ if (!are_interrupts_enabled()) {
+ kprintf("Interrupts disabled when trying to take Lock{%s}\n", m_name);
+ dump_backtrace();
+ hang();
+ }
+ ASSERT(!Scheduler::is_active());
+ for (;;) {
+ if (CAS(&m_lock, 1, 0) == 0) {
+ if (!m_holder || m_holder == current) {
+ m_holder = current;
+ ++m_level;
+ memory_barrier();
+ m_lock = 0;
+ return;
+ }
+ m_lock = 0;
+ }
+ Scheduler::donate_to(m_holder, m_name);
+ }
+}
+
+void Lock::unlock()
+{
+ for (;;) {
+ if (CAS(&m_lock, 1, 0) == 0) {
+ ASSERT(m_holder == current);
+ ASSERT(m_level);
+ --m_level;
+ if (m_level) {
+ memory_barrier();
+ m_lock = 0;
+ return;
+ }
+ m_holder = nullptr;
+ memory_barrier();
+ m_lock = 0;
+ return;
+ }
+ Scheduler::donate_to(m_holder, m_name);
+ }
+}
+
+bool Lock::unlock_if_locked()
+{
+ for (;;) {
+ if (CAS(&m_lock, 1, 0) == 0) {
+ if (m_level == 0) {
+ memory_barrier();
+ m_lock = 0;
+ return false;
+ }
+ ASSERT(m_holder == current);
+ ASSERT(m_level);
+ --m_level;
+ if (m_level) {
+ memory_barrier();
+ m_lock = 0;
+ return false;
+ }
+ m_holder = nullptr;
+ memory_barrier();
+ m_lock = 0;
+ return true;
+ }
+ }
+}