BarryServer : Git

All the code for all my projects
// BarryServer : Git / Nucleus / blob / master / lib / object / lock.c

// Related

Nucleus

Barry Preemptive and lockless scheduler a1eaf26 (3 years, 1 month ago)
/*
 * This file implements spinlocks.  It makes heavy use of GCC's atomic built-ins
 * for syncronisation.  The spinlocks have some simple mechanisms for preventing
 * deadlocks.  Each spinlock knowns which CPU/task is holding it, and can allow
 * that CPU/task to acquire it multiple times and safely release it.
 */

#include <nucleus/kernel.h>
#include <nucleus/object.h>
#include <nucleus/task.h>

/* Check if already holding */
static inline int
holding(Spinlock *lock)
{
	return (lock->locked && lock->owner == current);
}

/* Initialise a lock */
void
init_lock(Spinlock *lock)
{
	lock->locked = 0;
	lock->usage = 0;
}

/* Acquire a lock */
void
acquire(Spinlock *lock)
{
	if (!holding(lock)) {
		while (__atomic_test_and_set(&lock->locked, __ATOMIC_ACQUIRE))
			asm volatile("pause");
		lock->owner = current;
	}
	__atomic_add_fetch(&lock->usage, 1, __ATOMIC_RELAXED);
}

/* Release a lock */
void
release(Spinlock *lock)
{
	ASSERT(holding(lock));
	if (!__atomic_sub_fetch(&lock->usage, 1, __ATOMIC_RELAXED)) {
		__atomic_clear(&lock->locked, __ATOMIC_RELEASE);
		lock->owner = NULL;
	}
}