58 lines
1.2 KiB
C
58 lines
1.2 KiB
C
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
|
* This file is part of ToaruOS and is released under the terms
|
|
* of the NCSA / University of Illinois License - see LICENSE.md
|
|
* Copyright (C) 2015 Dale Weiler
|
|
*
|
|
* Spin locks with waiters
|
|
*
|
|
*/
|
|
#include <kernel/system.h>
|
|
|
|
static inline int arch_atomic_swap(volatile int * x, int v) {
|
|
asm("xchg %0, %1" : "=r"(v), "=m"(*x) : "0"(v) : "memory");
|
|
return v;
|
|
}
|
|
|
|
static inline void arch_atomic_store(volatile int * p, int x) {
|
|
asm("movl %1, %0" : "=m"(*p) : "r"(x) : "memory");
|
|
}
|
|
|
|
static inline void arch_atomic_inc(volatile int * x) {
|
|
asm("lock; incl %0" : "=m"(*x) : "m"(*x) : "memory");
|
|
}
|
|
|
|
static inline void arch_atomic_dec(volatile int * x) {
|
|
asm("lock; decl %0" : "=m"(*x) : "m"(*x) : "memory");
|
|
}
|
|
|
|
void spin_wait(volatile int * addr, volatile int * waiters) {
|
|
if (waiters) {
|
|
arch_atomic_inc(waiters);
|
|
}
|
|
while (*addr) {
|
|
switch_task(1);
|
|
}
|
|
if (waiters) {
|
|
arch_atomic_dec(waiters);
|
|
}
|
|
}
|
|
|
|
void spin_lock(spin_lock_t lock) {
|
|
while (arch_atomic_swap(lock, 1)) {
|
|
spin_wait(lock, lock+1);
|
|
}
|
|
}
|
|
|
|
void spin_init(spin_lock_t lock) {
|
|
lock[0] = 0;
|
|
lock[1] = 0;
|
|
}
|
|
|
|
void spin_unlock(spin_lock_t lock) {
|
|
if (lock[0]) {
|
|
arch_atomic_store(lock, 0);
|
|
if (lock[1])
|
|
switch_task(1);
|
|
}
|
|
}
|