Orion
Barry Importing existing Orion kernel d41a53c (3 years, 2 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();
}