BarryServer : Git

All the code for all my projects
// BarryServer : Git / Orion / commit / d41a53cbc7d055b1c00cf0a339dbed6925f4f02c / spinlock.c

// Related

Orion

Barry Importing existing Orion kernel d41a53c (2 years, 4 months ago)
diff --git a/spinlock.c b/spinlock.c
new file mode 100644
index 0000000..059f65e
--- /dev/null
+++ b/spinlock.c
@@ -0,0 +1,70 @@
+/*
+ * This file contains the implementation of spinlocks.  It makes heavy use of
+ * GCC's atomic built-ins for synchronization.  The spinlocks have some simple
+ * mechanisms for preventing deadlocks.  Each spinlock knows which CPU/task is
+ * holding it, and can allow that CPU/task to acquire it multiple times and
+ * safely release it.
+ */
+
+#include <stdint.h>
+#include "task/task.h"
+#include "proc/proc.h"
+#include "spinlock.h"
+#include "screen.h"
+#include "io.h"
+
+/* Check if already holding */
+static uint8_t
+holding(Spinlock *lock)
+{
+	uint8_t r;
+	r = lock->locked;
+	r &= (current ? lock->task == current->tid : lock->cpu == CPUID);
+	return r;
+}
+
+/* Create a new lock */
+void
+init_lock(Spinlock *lock)
+{
+	lock->locked = 0;
+	lock->task = 0;
+	lock->cpu = 0;
+	lock->ref = 0;
+}
+
+/* Acquire a lock */
+void
+acquire(Spinlock *lock)
+{
+	/*
+	 * Reference count the lock so it can be safely acquired by the same
+	 * holder multiple times.  This stops a lock from deadlocking itself.
+	 */
+	if (holding(lock)) {
+		lock->ref++;
+		return;
+	}
+	while (!__sync_bool_compare_and_swap(&lock->locked, 0, 1))
+		asm volatile("pause");
+	__sync_synchronize();
+	if (current)
+		lock->task = current->tid;
+	lock->cpu = CPUID;
+}
+
+/* Release a lock */
+void
+release(Spinlock *lock)
+{
+	if (!holding(lock))
+		panic("Cannot release unheld lock");
+	if (lock->ref) {
+		lock->ref--;
+		return;
+	}
+	lock->task = 0;
+	lock->cpu = 0;
+	__sync_lock_release(&lock->locked);
+	__sync_synchronize();
+}