libnx/nx/source/kernel/mutex.c
2017-11-17 16:15:28 +01:00

67 lines
1.5 KiB
C

// Copyright 2017 plutoo
#include <switch.h>
#include "../internal.h"
#define HAS_LISTENERS 0x40000000
static u32 _GetTag() {
return getThreadVars()->handle;
}
void mutexLock(Mutex* m) {
u32 self = _GetTag();
while (1) {
u32 cur = __sync_val_compare_and_swap((u32*)m, 0, self);
if (cur == 0) {
// We won the race!
return;
}
if ((cur &~ HAS_LISTENERS) == self) {
// Kernel assigned it to us!
return;
}
if (cur & HAS_LISTENERS) {
// The flag is already set, we can use the syscall.
svcArbitrateLock(cur &~ HAS_LISTENERS, (u32*)m, self);
}
else {
// The flag is not set, we need to set it.
u32 old = __sync_val_compare_and_swap((u32*)m, cur, cur | HAS_LISTENERS);
if (old == cur) {
// Flag was set successfully.
svcArbitrateLock(cur &~ HAS_LISTENERS, (u32*)m, self);
}
}
}
}
void mutexUnlock(Mutex* m) {
u32 old = __sync_lock_test_and_set((u32*)m, 0);
if (old & HAS_LISTENERS) {
svcArbitrateUnlock((u32*)m);
}
}
void rmutexLock(RMutex* m) {
if (m->thread_tag == _GetTag()) {
m->counter++;
}
else {
mutexLock(&m->lock);
m->thread_tag = _GetTag();
}
}
void rmutexUnlock(RMutex* m) {
if (--m->counter == 0) {
m->thread_tag = 0;
mutexUnlock(&m->lock);
}
}