BarryServer : Git

All the code for all my projects
// BarryServer : Git / Orion / blob / 7ae31b03c38925f5d527e6303765925586731209 / spinlock.c

// Related

Orion

Barry Importing existing Orion kernel d41a53c (2 years, 4 months ago)
/*
 * 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();
}