Introducing mutex

This commit is contained in:
plutoo 2017-09-25 00:04:03 +02:00
parent 983c708830
commit 2a981d5c69
5 changed files with 101 additions and 0 deletions

View File

@ -15,6 +15,7 @@ extern "C" {
#include <switch/heap.h> #include <switch/heap.h>
#include <switch/kernel/tmem.h> #include <switch/kernel/tmem.h>
#include <switch/kernel/mutex.h>
#include <switch/services/sm.h> #include <switch/services/sm.h>
#include <switch/services/bsd.h> #include <switch/services/bsd.h>

View File

@ -0,0 +1,16 @@
// Copyright 2017 plutoo
typedef struct {
u32 Tag;
} Mutex;
typedef struct {
u32 Owner;
Mutex Lock;
size_t Count;
} RMutex;
void mutexLock(Mutex* m);
void mutexUnlock(Mutex* m);
void rmutexLock(RMutex* m);
void rmutexUnlock(RMutex* m);

View File

@ -48,6 +48,8 @@ Result svcSleepThread(u64 nano);
Result svcCloseHandle(Handle handle); Result svcCloseHandle(Handle handle);
Result svcCreateTransferMemory(Handle* out, void* addr, size_t size, u32 perm); Result svcCreateTransferMemory(Handle* out, void* addr, size_t size, u32 perm);
Result svcWaitSynchronization(s32* index, const Handle* handles, s32 handleCount, u64 timeout); Result svcWaitSynchronization(s32* index, const Handle* handles, s32 handleCount, u64 timeout);
Result svcArbitrateLock(u32 wait_tag, u32* tag_location, u32 self_tag);
Result svcArbitrateUnlock(u32* tag_location);
Result svcConnectToNamedPort(Handle* session, const char* name); Result svcConnectToNamedPort(Handle* session, const char* name);
Result svcSendSyncRequest(Handle session); Result svcSendSyncRequest(Handle session);
Result svcBreak(u32 breakReason, u64 inval1, u64 inval2); Result svcBreak(u32 breakReason, u64 inval1, u64 inval2);

74
nx/source/kernel/mutex.c Normal file
View File

@ -0,0 +1,74 @@
// Copyright 2017 plutoo
#include <switch.h>
#define HAS_LISTENERS 0x40000000
static u32 _GetTag() {
// todo: Needs filling in at thread creation.
// todo: Must always be assigned non-zero.
return ((u32*)armGetTls()) [0x1FC/4];
}
void mutexLock(Mutex* m) {
u32 self = _GetTag();
u32 cur = __sync_val_compare_and_swap(&m->Tag, 0, self);
if (cur == 0) {
// We won the race!
return;
}
while (1) {
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, &m->Tag, self);
}
else {
// The flag is not set, we need to set it.
u32 old = __sync_val_compare_and_swap(&m->Tag, cur, cur | HAS_LISTENERS);
if (old == cur) {
// Flag was set successfully.
svcArbitrateLock(cur &~ HAS_LISTENERS, &m->Tag, self);
}
}
cur = __sync_val_compare_and_swap(&m->Tag, 0, self);
if (cur == 0) {
// We won the race!
return;
}
}
}
void mutexUnlock(Mutex* m) {
u32 self = _GetTag();
u32 old = __sync_val_compare_and_swap(&m->Tag, self, 0);
if (old & HAS_LISTENERS) {
svcArbitrateUnlock(&m->Tag);
}
}
void rmutexLock(RMutex* m) {
if (m->Owner == _GetTag()) {
m->Count++;
}
else {
mutexLock(&m->Lock);
m->Owner = _GetTag();
}
}
void rmutexUnlock(RMutex* m) {
if (--m->Count == 0) {
m->Owner = 0;
mutexUnlock(&m->Lock);
}
}

View File

@ -58,6 +58,14 @@ SVC_BEGIN svcWaitSynchronization
ret ret
SVC_END SVC_END
SVC_BEGIN svcArbitrateLock
svc 0x1a
SVC_END
SVC_BEGIN svcArbitrateUnlock
svc 0x1b
SVC_END
SVC_BEGIN svcConnectToNamedPort SVC_BEGIN svcConnectToNamedPort
str x0, [sp, #-16]! str x0, [sp, #-16]!
svc 0x1F svc 0x1F