mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 04:22:50 +02:00
Merge branch 'master' of github.com:switchbrew/libnx
This commit is contained in:
commit
c14d9baffb
@ -15,6 +15,7 @@ extern "C" {
|
||||
#include <switch/heap.h>
|
||||
|
||||
#include <switch/kernel/tmem.h>
|
||||
#include <switch/kernel/mutex.h>
|
||||
|
||||
#include <switch/services/sm.h>
|
||||
#include <switch/services/bsd.h>
|
||||
|
16
nx/include/switch/kernel/mutex.h
Normal file
16
nx/include/switch/kernel/mutex.h
Normal 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);
|
@ -48,6 +48,8 @@ Result svcSleepThread(u64 nano);
|
||||
Result svcCloseHandle(Handle handle);
|
||||
Result svcCreateTransferMemory(Handle* out, void* addr, size_t size, u32 perm);
|
||||
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 svcSendSyncRequest(Handle session);
|
||||
Result svcBreak(u32 breakReason, u64 inval1, u64 inval2);
|
||||
|
74
nx/source/kernel/mutex.c
Normal file
74
nx/source/kernel/mutex.c
Normal 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);
|
||||
}
|
||||
}
|
@ -58,6 +58,14 @@ SVC_BEGIN svcWaitSynchronization
|
||||
ret
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcArbitrateLock
|
||||
svc 0x1a
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcArbitrateUnlock
|
||||
svc 0x1b
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcConnectToNamedPort
|
||||
str x0, [sp, #-16]!
|
||||
svc 0x1F
|
||||
|
Loading…
Reference in New Issue
Block a user