mirror of
https://github.com/Atmosphere-NX/Atmosphere-libs.git
synced 2025-08-08 16:39:27 +02:00
libstrat: namespace hossynch.hpp
This commit is contained in:
parent
8bae7b4a78
commit
ec2ea1e850
2
Makefile
2
Makefile
@ -16,7 +16,7 @@ include $(DEVKITPRO)/libnx/switch_rules
|
|||||||
# INCLUDES is a list of directories containing header files
|
# INCLUDES is a list of directories containing header files
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
TARGET := $(notdir $(CURDIR))
|
TARGET := $(notdir $(CURDIR))
|
||||||
SOURCES := source source/spl source/spl/smc source/updater source/patcher source/map source/rnd source/util source/sm source/cfg source/pm source/hid source/ldr source/kvdb
|
SOURCES := source source/os source/spl source/spl/smc source/updater source/patcher source/map source/rnd source/util source/sm source/cfg source/pm source/hid source/ldr source/kvdb
|
||||||
DATA := data
|
DATA := data
|
||||||
INCLUDES := include
|
INCLUDES := include
|
||||||
|
|
||||||
|
@ -26,24 +26,20 @@
|
|||||||
#include "stratosphere/version_check.hpp"
|
#include "stratosphere/version_check.hpp"
|
||||||
|
|
||||||
#include "stratosphere/auto_handle.hpp"
|
#include "stratosphere/auto_handle.hpp"
|
||||||
#include "stratosphere/hossynch.hpp"
|
|
||||||
#include "stratosphere/message_queue.hpp"
|
|
||||||
#include "stratosphere/iwaitable.hpp"
|
#include "stratosphere/iwaitable.hpp"
|
||||||
#include "stratosphere/event.hpp"
|
#include "stratosphere/event.hpp"
|
||||||
|
|
||||||
#include "stratosphere/waitable_manager.hpp"
|
#include "stratosphere/waitable_manager.hpp"
|
||||||
|
|
||||||
#include "stratosphere/ipc.hpp"
|
#include "stratosphere/ipc.hpp"
|
||||||
|
|
||||||
#include "stratosphere/mitm.hpp"
|
#include "stratosphere/mitm.hpp"
|
||||||
|
|
||||||
#include "stratosphere/services.hpp"
|
|
||||||
|
|
||||||
#include "stratosphere/results.hpp"
|
#include "stratosphere/results.hpp"
|
||||||
|
|
||||||
#include "stratosphere/on_crash.hpp"
|
#include "stratosphere/on_crash.hpp"
|
||||||
|
|
||||||
#include "stratosphere/svc.hpp"
|
#include "stratosphere/svc.hpp"
|
||||||
|
#include "stratosphere/os.hpp"
|
||||||
#include "stratosphere/cfg.hpp"
|
#include "stratosphere/cfg.hpp"
|
||||||
#include "stratosphere/fatal.hpp"
|
#include "stratosphere/fatal.hpp"
|
||||||
#include "stratosphere/hid.hpp"
|
#include "stratosphere/hid.hpp"
|
||||||
|
@ -53,7 +53,7 @@ class IEvent : public IWaitable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Clear() {
|
void Clear() {
|
||||||
std::scoped_lock<HosMutex> lock(this->sig_lock);
|
std::scoped_lock lock(this->sig_lock);
|
||||||
this->is_signaled = false;
|
this->is_signaled = false;
|
||||||
if (this->w_h != INVALID_HANDLE) {
|
if (this->w_h != INVALID_HANDLE) {
|
||||||
svcClearEvent(this->w_h);
|
svcClearEvent(this->w_h);
|
||||||
@ -63,7 +63,7 @@ class IEvent : public IWaitable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Signal() {
|
void Signal() {
|
||||||
std::scoped_lock<HosMutex> lock(this->sig_lock);
|
std::scoped_lock lock(this->sig_lock);
|
||||||
|
|
||||||
if (this->w_h == INVALID_HANDLE && this->r_h != INVALID_HANDLE) {
|
if (this->w_h == INVALID_HANDLE && this->r_h != INVALID_HANDLE) {
|
||||||
/* We can't signal an event if we only have a read handle. */
|
/* We can't signal an event if we only have a read handle. */
|
||||||
|
@ -1,299 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms and conditions of the GNU General Public License,
|
|
||||||
* version 2, as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <switch.h>
|
|
||||||
#include <switch/arm/counter.h>
|
|
||||||
#include <mutex>
|
|
||||||
#include "results.hpp"
|
|
||||||
#include "auto_handle.hpp"
|
|
||||||
|
|
||||||
class HosMutex {
|
|
||||||
private:
|
|
||||||
Mutex m;
|
|
||||||
Mutex *GetMutex() {
|
|
||||||
return &this->m;
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
HosMutex() {
|
|
||||||
mutexInit(GetMutex());
|
|
||||||
}
|
|
||||||
|
|
||||||
void lock() {
|
|
||||||
mutexLock(GetMutex());
|
|
||||||
}
|
|
||||||
|
|
||||||
void unlock() {
|
|
||||||
mutexUnlock(GetMutex());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool try_lock() {
|
|
||||||
return mutexTryLock(GetMutex());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Lock() {
|
|
||||||
lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Unlock() {
|
|
||||||
unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TryLock() {
|
|
||||||
return try_lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
friend class HosCondVar;
|
|
||||||
};
|
|
||||||
|
|
||||||
class HosRecursiveMutex {
|
|
||||||
private:
|
|
||||||
RMutex m;
|
|
||||||
RMutex *GetMutex() {
|
|
||||||
return &this->m;
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
HosRecursiveMutex() {
|
|
||||||
rmutexInit(GetMutex());
|
|
||||||
}
|
|
||||||
|
|
||||||
void lock() {
|
|
||||||
rmutexLock(GetMutex());
|
|
||||||
}
|
|
||||||
|
|
||||||
void unlock() {
|
|
||||||
rmutexUnlock(GetMutex());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool try_lock() {
|
|
||||||
return rmutexTryLock(GetMutex());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Lock() {
|
|
||||||
lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Unlock() {
|
|
||||||
unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TryLock() {
|
|
||||||
return try_lock();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class HosCondVar {
|
|
||||||
private:
|
|
||||||
CondVar cv;
|
|
||||||
public:
|
|
||||||
HosCondVar() {
|
|
||||||
condvarInit(&cv);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result TimedWait(u64 timeout, HosMutex *hm) {
|
|
||||||
return TimedWait(timeout, hm->GetMutex());
|
|
||||||
}
|
|
||||||
|
|
||||||
Result Wait(HosMutex *hm) {
|
|
||||||
return Wait(hm->GetMutex());
|
|
||||||
}
|
|
||||||
|
|
||||||
Result TimedWait(u64 timeout, Mutex *m) {
|
|
||||||
return condvarWaitTimeout(&cv, m, timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result Wait(Mutex *m) {
|
|
||||||
return condvarWait(&cv, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result Wake(int num) {
|
|
||||||
return condvarWake(&cv, num);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result WakeOne() {
|
|
||||||
return condvarWakeOne(&cv);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result WakeAll() {
|
|
||||||
return condvarWakeAll(&cv);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class HosSemaphore {
|
|
||||||
private:
|
|
||||||
Semaphore s;
|
|
||||||
public:
|
|
||||||
HosSemaphore() {
|
|
||||||
semaphoreInit(&s, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
HosSemaphore(u64 c) {
|
|
||||||
semaphoreInit(&s, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Signal() {
|
|
||||||
semaphoreSignal(&s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Wait() {
|
|
||||||
semaphoreWait(&s);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TryWait() {
|
|
||||||
return semaphoreTryWait(&s);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class TimeoutHelper {
|
|
||||||
private:
|
|
||||||
u64 end_tick;
|
|
||||||
public:
|
|
||||||
TimeoutHelper(u64 ns) {
|
|
||||||
/* Special case zero-time timeouts. */
|
|
||||||
if (ns == 0) {
|
|
||||||
end_tick = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 cur_tick = armGetSystemTick();
|
|
||||||
this->end_tick = cur_tick + NsToTick(ns) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline u64 NsToTick(u64 ns) {
|
|
||||||
return (ns * 12) / 625;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline u64 TickToNs(u64 tick) {
|
|
||||||
return (tick * 625) / 12;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 NsUntilTimeout() {
|
|
||||||
u64 diff = TickToNs(this->end_tick - armGetSystemTick());
|
|
||||||
|
|
||||||
if (TimedOut()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TimedOut() {
|
|
||||||
if (this->end_tick == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return armGetSystemTick() >= this->end_tick;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class HosSignal {
|
|
||||||
private:
|
|
||||||
CondVar cv;
|
|
||||||
Mutex m;
|
|
||||||
bool signaled;
|
|
||||||
public:
|
|
||||||
HosSignal() {
|
|
||||||
condvarInit(&cv);
|
|
||||||
mutexInit(&m);
|
|
||||||
signaled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Signal() {
|
|
||||||
mutexLock(&m);
|
|
||||||
signaled = true;
|
|
||||||
condvarWakeAll(&cv);
|
|
||||||
mutexUnlock(&m);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reset() {
|
|
||||||
mutexLock(&m);
|
|
||||||
signaled = false;
|
|
||||||
mutexUnlock(&m);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Wait(bool reset = false) {
|
|
||||||
mutexLock(&m);
|
|
||||||
|
|
||||||
while (!signaled) {
|
|
||||||
condvarWait(&cv, &m);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reset) {
|
|
||||||
this->signaled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutexUnlock(&m);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TryWait(bool reset = false) {
|
|
||||||
mutexLock(&m);
|
|
||||||
|
|
||||||
bool success = signaled;
|
|
||||||
if (reset) {
|
|
||||||
this->signaled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutexUnlock(&m);
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result TimedWait(u64 ns, bool reset = false) {
|
|
||||||
mutexLock(&m);
|
|
||||||
TimeoutHelper timeout_helper(ns);
|
|
||||||
|
|
||||||
while (!signaled) {
|
|
||||||
if (R_FAILED(condvarWaitTimeout(&cv, &m, timeout_helper.NsUntilTimeout()))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reset) {
|
|
||||||
this->signaled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutexUnlock(&m);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class HosThread {
|
|
||||||
private:
|
|
||||||
Thread thr = {};
|
|
||||||
public:
|
|
||||||
HosThread() {}
|
|
||||||
|
|
||||||
Result Initialize(ThreadFunc entry, void *arg, size_t stack_sz, int prio, int cpuid = -2) {
|
|
||||||
return threadCreate(&this->thr, entry, arg, stack_sz, prio, cpuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle GetHandle() const {
|
|
||||||
return this->thr.handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result Start() {
|
|
||||||
return threadStart(&this->thr);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result Join() {
|
|
||||||
R_TRY(threadWaitForExit(&this->thr));
|
|
||||||
R_TRY(threadClose(&this->thr));
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result CancelSynchronization() {
|
|
||||||
return svcCancelSynchronization(this->thr.handle);
|
|
||||||
}
|
|
||||||
};
|
|
@ -17,9 +17,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
|
#include "os.hpp"
|
||||||
|
|
||||||
#include "waitable_manager_base.hpp"
|
#include "waitable_manager_base.hpp"
|
||||||
#include "hossynch.hpp"
|
|
||||||
|
|
||||||
class IWaitable {
|
class IWaitable {
|
||||||
private:
|
private:
|
||||||
@ -27,7 +27,7 @@ class IWaitable {
|
|||||||
bool is_deferred = false;
|
bool is_deferred = false;
|
||||||
WaitableManagerBase *manager = nullptr;
|
WaitableManagerBase *manager = nullptr;
|
||||||
protected:
|
protected:
|
||||||
HosMutex sig_lock;
|
sts::os::Mutex sig_lock;
|
||||||
bool is_signaled = false;
|
bool is_signaled = false;
|
||||||
public:
|
public:
|
||||||
virtual ~IWaitable() = default;
|
virtual ~IWaitable() = default;
|
||||||
@ -38,7 +38,7 @@ class IWaitable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool IsSignaled() {
|
bool IsSignaled() {
|
||||||
std::scoped_lock<HosMutex> lock(this->sig_lock);
|
std::scoped_lock lock(this->sig_lock);
|
||||||
return this->is_signaled;
|
return this->is_signaled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
|
#include "../os.hpp"
|
||||||
|
|
||||||
#include "kvdb_bounded_string.hpp"
|
#include "kvdb_bounded_string.hpp"
|
||||||
|
|
||||||
@ -66,7 +67,7 @@ namespace sts::kvdb {
|
|||||||
bool Contains(const void *key, size_t key_size);
|
bool Contains(const void *key, size_t key_size);
|
||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
HosMutex lock;
|
os::Mutex lock;
|
||||||
Path dir_path;
|
Path dir_path;
|
||||||
Cache cache;
|
Cache cache;
|
||||||
private:
|
private:
|
||||||
|
@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms and conditions of the GNU General Public License,
|
|
||||||
* version 2, as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <switch.h>
|
|
||||||
#include "hossynch.hpp"
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
class HosMessageQueue {
|
|
||||||
private:
|
|
||||||
HosMutex queue_lock;
|
|
||||||
HosCondVar cv_not_full;
|
|
||||||
HosCondVar cv_not_empty;
|
|
||||||
std::unique_ptr<uintptr_t[]> buffer;
|
|
||||||
size_t capacity;
|
|
||||||
|
|
||||||
size_t count = 0;
|
|
||||||
size_t offset = 0;
|
|
||||||
public:
|
|
||||||
HosMessageQueue(size_t c) : capacity(c) {
|
|
||||||
this->buffer = std::make_unique<uintptr_t[]>(this->capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
HosMessageQueue(std::unique_ptr<uintptr_t[]> buf, size_t c) : buffer(std::move(buf)), capacity(c) { }
|
|
||||||
|
|
||||||
/* Sending (FIFO functionality) */
|
|
||||||
void Send(uintptr_t data);
|
|
||||||
bool TrySend(uintptr_t data);
|
|
||||||
bool TimedSend(uintptr_t data, u64 timeout);
|
|
||||||
|
|
||||||
/* Sending (LIFO functionality) */
|
|
||||||
void SendNext(uintptr_t data);
|
|
||||||
bool TrySendNext(uintptr_t data);
|
|
||||||
bool TimedSendNext(uintptr_t data, u64 timeout);
|
|
||||||
|
|
||||||
/* Receive functionality */
|
|
||||||
void Receive(uintptr_t *out);
|
|
||||||
bool TryReceive(uintptr_t *out);
|
|
||||||
bool TimedReceive(uintptr_t *out, u64 timeout);
|
|
||||||
|
|
||||||
/* Peek functionality */
|
|
||||||
void Peek(uintptr_t *out);
|
|
||||||
bool TryPeek(uintptr_t *out);
|
|
||||||
bool TimedPeek(uintptr_t *out, u64 timeout);
|
|
||||||
private:
|
|
||||||
bool IsFull() {
|
|
||||||
return this->count >= this->capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsEmpty() {
|
|
||||||
return this->count == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SendInternal(uintptr_t data);
|
|
||||||
void SendNextInternal(uintptr_t data);
|
|
||||||
uintptr_t ReceiveInternal();
|
|
||||||
uintptr_t PeekInternal();
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
@ -15,7 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <switch.h>
|
||||||
|
|
||||||
#include "ipc.hpp"
|
#include "os/os_mutex.hpp"
|
||||||
|
#include "os/os_condvar.hpp"
|
||||||
#include "services/dmntcht.h"
|
#include "os/os_semaphore.hpp"
|
||||||
|
#include "os/os_timeout_helper.hpp"
|
||||||
|
#include "os/os_event.hpp"
|
||||||
|
#include "os/os_thread.hpp"
|
||||||
|
#include "os/os_message_queue.hpp"
|
69
include/stratosphere/os/os_condvar.hpp
Normal file
69
include/stratosphere/os/os_condvar.hpp
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "os_mutex.hpp"
|
||||||
|
|
||||||
|
namespace sts::os {
|
||||||
|
|
||||||
|
class ConditionVariable {
|
||||||
|
NON_COPYABLE(ConditionVariable);
|
||||||
|
NON_MOVEABLE(ConditionVariable);
|
||||||
|
private:
|
||||||
|
CondVar cv;
|
||||||
|
public:
|
||||||
|
ConditionVariable() {
|
||||||
|
condvarInit(&cv);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result TimedWait(::Mutex *m, u64 timeout) {
|
||||||
|
return condvarWaitTimeout(&cv, m, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Wait(::Mutex *m) {
|
||||||
|
return condvarWait(&cv, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result TimedWait(os::Mutex *m, u64 timeout) {
|
||||||
|
return TimedWait(m->GetMutex(), timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Wait(os::Mutex *m) {
|
||||||
|
return Wait(m->GetMutex());
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Wake(int num) {
|
||||||
|
return condvarWake(&cv, num);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result WakeOne() {
|
||||||
|
return condvarWakeOne(&cv);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result WakeAll() {
|
||||||
|
return condvarWakeAll(&cv);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Signal() {
|
||||||
|
return this->WakeOne();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Broadcast() {
|
||||||
|
return this->WakeAll();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
113
include/stratosphere/os/os_event.hpp
Normal file
113
include/stratosphere/os/os_event.hpp
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "os_mutex.hpp"
|
||||||
|
#include "os_condvar.hpp"
|
||||||
|
#include "os_timeout_helper.hpp"
|
||||||
|
|
||||||
|
namespace sts::os {
|
||||||
|
|
||||||
|
class Event {
|
||||||
|
NON_COPYABLE(Event);
|
||||||
|
NON_MOVEABLE(Event);
|
||||||
|
private:
|
||||||
|
Mutex m;
|
||||||
|
ConditionVariable cv;
|
||||||
|
bool auto_clear;
|
||||||
|
bool signaled;
|
||||||
|
u64 counter = 0;
|
||||||
|
public:
|
||||||
|
Event(bool a = true, bool s = false) : auto_clear(a), signaled(s) {}
|
||||||
|
|
||||||
|
void Signal() {
|
||||||
|
std::scoped_lock lk(this->m);
|
||||||
|
|
||||||
|
/* If we're already signaled, nothing more to do. */
|
||||||
|
if (this->signaled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->signaled = true;
|
||||||
|
|
||||||
|
/* Signal! */
|
||||||
|
if (this->auto_clear) {
|
||||||
|
/* If we're auto clear, signal one thread, which will clear. */
|
||||||
|
this->cv.Signal();
|
||||||
|
} else {
|
||||||
|
/* If we're manual clear, increment counter and wake all. */
|
||||||
|
this->counter++;
|
||||||
|
this->cv.Broadcast();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Waitable auto-wakeup. */
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset() {
|
||||||
|
std::scoped_lock lk(this->m);
|
||||||
|
this->signaled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wait() {
|
||||||
|
std::scoped_lock lk(this->m);
|
||||||
|
|
||||||
|
u64 cur_counter = this->counter;
|
||||||
|
while (!this->signaled) {
|
||||||
|
if (this->counter != cur_counter) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this->cv.Wait(&this->m);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->auto_clear) {
|
||||||
|
this->signaled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TryWait() {
|
||||||
|
std::scoped_lock lk(this->m);
|
||||||
|
|
||||||
|
const bool success = this->signaled;
|
||||||
|
if (this->auto_clear) {
|
||||||
|
this->signaled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TimedWait(u64 ns) {
|
||||||
|
TimeoutHelper timeout_helper(ns);
|
||||||
|
std::scoped_lock lk(this->m);
|
||||||
|
|
||||||
|
u64 cur_counter = this->counter;
|
||||||
|
while (!this->signaled) {
|
||||||
|
if (this->counter != cur_counter) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (R_FAILED(this->cv.TimedWait(&this->m, timeout_helper.NsUntilTimeout()))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->auto_clear) {
|
||||||
|
this->signaled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
77
include/stratosphere/os/os_message_queue.hpp
Normal file
77
include/stratosphere/os/os_message_queue.hpp
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <memory>
|
||||||
|
#include "os_mutex.hpp"
|
||||||
|
#include "os_condvar.hpp"
|
||||||
|
|
||||||
|
namespace sts::os {
|
||||||
|
|
||||||
|
class MessageQueue {
|
||||||
|
NON_COPYABLE(MessageQueue);
|
||||||
|
NON_MOVEABLE(MessageQueue);
|
||||||
|
private:
|
||||||
|
Mutex queue_lock;
|
||||||
|
ConditionVariable cv_not_full;
|
||||||
|
ConditionVariable cv_not_empty;
|
||||||
|
std::unique_ptr<uintptr_t[]> buffer;
|
||||||
|
size_t capacity;
|
||||||
|
|
||||||
|
size_t count = 0;
|
||||||
|
size_t offset = 0;
|
||||||
|
private:
|
||||||
|
bool IsFull() const {
|
||||||
|
return this->count >= this->capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsEmpty() const {
|
||||||
|
return this->count == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SendInternal(uintptr_t data);
|
||||||
|
void SendNextInternal(uintptr_t data);
|
||||||
|
uintptr_t ReceiveInternal();
|
||||||
|
uintptr_t PeekInternal();
|
||||||
|
public:
|
||||||
|
MessageQueue(size_t c) : capacity(c) {
|
||||||
|
this->buffer = std::make_unique<uintptr_t[]>(this->capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageQueue(std::unique_ptr<uintptr_t[]> buf, size_t c) : buffer(std::move(buf)), capacity(c) { }
|
||||||
|
|
||||||
|
/* Sending (FIFO functionality) */
|
||||||
|
void Send(uintptr_t data);
|
||||||
|
bool TrySend(uintptr_t data);
|
||||||
|
bool TimedSend(uintptr_t data, u64 timeout);
|
||||||
|
|
||||||
|
/* Sending (LIFO functionality) */
|
||||||
|
void SendNext(uintptr_t data);
|
||||||
|
bool TrySendNext(uintptr_t data);
|
||||||
|
bool TimedSendNext(uintptr_t data, u64 timeout);
|
||||||
|
|
||||||
|
/* Receive functionality */
|
||||||
|
void Receive(uintptr_t *out);
|
||||||
|
bool TryReceive(uintptr_t *out);
|
||||||
|
bool TimedReceive(uintptr_t *out, u64 timeout);
|
||||||
|
|
||||||
|
/* Peek functionality */
|
||||||
|
void Peek(uintptr_t *out);
|
||||||
|
bool TryPeek(uintptr_t *out);
|
||||||
|
bool TimedPeek(uintptr_t *out, u64 timeout);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
103
include/stratosphere/os/os_mutex.hpp
Normal file
103
include/stratosphere/os/os_mutex.hpp
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <mutex>
|
||||||
|
#include <switch.h>
|
||||||
|
#include "../util.hpp"
|
||||||
|
|
||||||
|
namespace sts::os {
|
||||||
|
|
||||||
|
class ConditionVariable;
|
||||||
|
|
||||||
|
class Mutex {
|
||||||
|
NON_COPYABLE(Mutex);
|
||||||
|
NON_MOVEABLE(Mutex);
|
||||||
|
friend class sts::os::ConditionVariable;
|
||||||
|
private:
|
||||||
|
::Mutex m;
|
||||||
|
private:
|
||||||
|
::Mutex *GetMutex() {
|
||||||
|
return &this->m;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
Mutex() {
|
||||||
|
mutexInit(GetMutex());
|
||||||
|
}
|
||||||
|
|
||||||
|
void lock() {
|
||||||
|
mutexLock(GetMutex());
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlock() {
|
||||||
|
mutexUnlock(GetMutex());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool try_lock() {
|
||||||
|
return mutexTryLock(GetMutex());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lock() {
|
||||||
|
lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Unlock() {
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TryLock() {
|
||||||
|
return try_lock();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class RecursiveMutex {
|
||||||
|
private:
|
||||||
|
::RMutex m;
|
||||||
|
private:
|
||||||
|
::RMutex *GetMutex() {
|
||||||
|
return &this->m;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
RecursiveMutex() {
|
||||||
|
rmutexInit(GetMutex());
|
||||||
|
}
|
||||||
|
|
||||||
|
void lock() {
|
||||||
|
rmutexLock(GetMutex());
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlock() {
|
||||||
|
rmutexUnlock(GetMutex());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool try_lock() {
|
||||||
|
return rmutexTryLock(GetMutex());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lock() {
|
||||||
|
lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Unlock() {
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TryLock() {
|
||||||
|
return try_lock();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
49
include/stratosphere/os/os_semaphore.hpp
Normal file
49
include/stratosphere/os/os_semaphore.hpp
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <switch.h>
|
||||||
|
|
||||||
|
namespace sts::os {
|
||||||
|
|
||||||
|
class Semaphore {
|
||||||
|
NON_COPYABLE(Semaphore);
|
||||||
|
NON_MOVEABLE(Semaphore);
|
||||||
|
private:
|
||||||
|
::Semaphore s;
|
||||||
|
public:
|
||||||
|
Semaphore() {
|
||||||
|
semaphoreInit(&s, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Semaphore(u64 c) {
|
||||||
|
semaphoreInit(&s, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Signal() {
|
||||||
|
semaphoreSignal(&s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wait() {
|
||||||
|
semaphoreWait(&s);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TryWait() {
|
||||||
|
return semaphoreTryWait(&s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
51
include/stratosphere/os/os_thread.hpp
Normal file
51
include/stratosphere/os/os_thread.hpp
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <switch.h>
|
||||||
|
|
||||||
|
namespace sts::os {
|
||||||
|
|
||||||
|
class Thread {
|
||||||
|
private:
|
||||||
|
::Thread thr = {};
|
||||||
|
public:
|
||||||
|
Thread() {}
|
||||||
|
|
||||||
|
Result Initialize(ThreadFunc entry, void *arg, size_t stack_sz, int prio, int cpuid = -2) {
|
||||||
|
return threadCreate(&this->thr, entry, arg, stack_sz, prio, cpuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle GetHandle() const {
|
||||||
|
return this->thr.handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Start() {
|
||||||
|
return threadStart(&this->thr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Join() {
|
||||||
|
R_TRY(threadWaitForExit(&this->thr));
|
||||||
|
R_TRY(threadClose(&this->thr));
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result CancelSynchronization() {
|
||||||
|
return svcCancelSynchronization(this->thr.handle);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
63
include/stratosphere/os/os_timeout_helper.hpp
Normal file
63
include/stratosphere/os/os_timeout_helper.hpp
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <switch.h>
|
||||||
|
|
||||||
|
namespace sts::os {
|
||||||
|
|
||||||
|
class TimeoutHelper {
|
||||||
|
private:
|
||||||
|
u64 end_tick;
|
||||||
|
public:
|
||||||
|
TimeoutHelper(u64 ns) {
|
||||||
|
/* Special case zero-time timeouts. */
|
||||||
|
if (ns == 0) {
|
||||||
|
end_tick = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 cur_tick = armGetSystemTick();
|
||||||
|
this->end_tick = cur_tick + NsToTick(ns) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr inline u64 NsToTick(u64 ns) {
|
||||||
|
return (ns * 12) / 625;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr inline u64 TickToNs(u64 tick) {
|
||||||
|
return (tick * 625) / 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TimedOut() const {
|
||||||
|
if (this->end_tick == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return armGetSystemTick() >= this->end_tick;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 NsUntilTimeout() const {
|
||||||
|
u64 diff = TickToNs(this->end_tick - armGetSystemTick());
|
||||||
|
|
||||||
|
if (this->TimedOut()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <cstdlib>
|
#include "defines.hpp"
|
||||||
|
#include "results.hpp"
|
||||||
#include "hossynch.hpp"
|
#include "os.hpp"
|
||||||
|
|
||||||
static inline uintptr_t GetIoMapping(const u64 io_addr, const u64 io_size) {
|
static inline uintptr_t GetIoMapping(const u64 io_addr, const u64 io_size) {
|
||||||
u64 vaddr;
|
u64 vaddr;
|
||||||
@ -115,11 +115,11 @@ static inline bool ShouldBlankProdInfo() {
|
|||||||
return should_blank_prodinfo;
|
return should_blank_prodinfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
HosRecursiveMutex &GetSmSessionMutex();
|
sts::os::RecursiveMutex &GetSmSessionMutex();
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
static void DoWithSmSession(F f) {
|
static void DoWithSmSession(F f) {
|
||||||
std::scoped_lock<HosRecursiveMutex &> lk(GetSmSessionMutex());
|
std::scoped_lock lk(GetSmSessionMutex());
|
||||||
{
|
{
|
||||||
R_ASSERT(smInitialize());
|
R_ASSERT(smInitialize());
|
||||||
f();
|
f();
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
#include "results.hpp"
|
#include "results.hpp"
|
||||||
|
#include "os.hpp"
|
||||||
#include "waitable_manager_base.hpp"
|
#include "waitable_manager_base.hpp"
|
||||||
#include "event.hpp"
|
#include "event.hpp"
|
||||||
#include "ipc.hpp"
|
#include "ipc.hpp"
|
||||||
@ -47,7 +48,7 @@ template<typename ManagerOptions = DefaultManagerOptions>
|
|||||||
class WaitableManager : public SessionManagerBase {
|
class WaitableManager : public SessionManagerBase {
|
||||||
private:
|
private:
|
||||||
/* Domain Manager */
|
/* Domain Manager */
|
||||||
HosMutex domain_lock;
|
sts::os::Mutex domain_lock;
|
||||||
std::array<uintptr_t, ManagerOptions::MaxDomains> domain_keys;
|
std::array<uintptr_t, ManagerOptions::MaxDomains> domain_keys;
|
||||||
std::array<bool, ManagerOptions::MaxDomains> is_domain_allocated;
|
std::array<bool, ManagerOptions::MaxDomains> is_domain_allocated;
|
||||||
std::array<DomainEntry, ManagerOptions::MaxDomainObjects> domain_objects;
|
std::array<DomainEntry, ManagerOptions::MaxDomainObjects> domain_objects;
|
||||||
@ -58,13 +59,13 @@ class WaitableManager : public SessionManagerBase {
|
|||||||
std::vector<IWaitable *> deferred_waitables;
|
std::vector<IWaitable *> deferred_waitables;
|
||||||
|
|
||||||
u32 num_extra_threads = 0;
|
u32 num_extra_threads = 0;
|
||||||
HosThread *threads = nullptr;
|
sts::os::Thread *threads = nullptr;
|
||||||
|
|
||||||
HosMutex process_lock;
|
sts::os::Mutex process_lock;
|
||||||
HosMutex signal_lock;
|
sts::os::Mutex signal_lock;
|
||||||
HosMutex add_lock;
|
sts::os::Mutex add_lock;
|
||||||
HosMutex cur_thread_lock;
|
sts::os::Mutex cur_thread_lock;
|
||||||
HosMutex deferred_lock;
|
sts::os::Mutex deferred_lock;
|
||||||
bool has_new_waitables = false;
|
bool has_new_waitables = false;
|
||||||
std::atomic<bool> should_stop = false;
|
std::atomic<bool> should_stop = false;
|
||||||
|
|
||||||
@ -75,7 +76,7 @@ class WaitableManager : public SessionManagerBase {
|
|||||||
WaitableManager(u32 n, u32 ss = 0x8000) : num_extra_threads(n-1) {
|
WaitableManager(u32 n, u32 ss = 0x8000) : num_extra_threads(n-1) {
|
||||||
u32 prio;
|
u32 prio;
|
||||||
if (num_extra_threads) {
|
if (num_extra_threads) {
|
||||||
threads = new HosThread[num_extra_threads];
|
threads = new sts::os::Thread[num_extra_threads];
|
||||||
R_ASSERT(svcGetThreadPriority(&prio, CUR_THREAD_HANDLE));
|
R_ASSERT(svcGetThreadPriority(&prio, CUR_THREAD_HANDLE));
|
||||||
for (unsigned int i = 0; i < num_extra_threads; i++) {
|
for (unsigned int i = 0; i < num_extra_threads; i++) {
|
||||||
R_ASSERT(threads[i].Initialize(&WaitableManager::ProcessLoop, this, ss, prio));
|
R_ASSERT(threads[i].Initialize(&WaitableManager::ProcessLoop, this, ss, prio));
|
||||||
@ -132,12 +133,12 @@ class WaitableManager : public SessionManagerBase {
|
|||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
void SetProcessingThreadHandle(Handle h) {
|
void SetProcessingThreadHandle(Handle h) {
|
||||||
std::scoped_lock<HosMutex> lk{this->cur_thread_lock};
|
std::scoped_lock lk{this->cur_thread_lock};
|
||||||
this->cur_thread_handle = h;
|
this->cur_thread_handle = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle GetProcessingThreadHandle() {
|
Handle GetProcessingThreadHandle() {
|
||||||
std::scoped_lock<HosMutex> lk{this->cur_thread_lock};
|
std::scoped_lock lk{this->cur_thread_lock};
|
||||||
return this->cur_thread_handle;
|
return this->cur_thread_handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ namespace sts::cfg {
|
|||||||
constexpr u64 InitialProcessIdMaxDeprecated = 0x50;
|
constexpr u64 InitialProcessIdMaxDeprecated = 0x50;
|
||||||
|
|
||||||
/* Privileged process globals. */
|
/* Privileged process globals. */
|
||||||
HosMutex g_lock;
|
os::Mutex g_lock;
|
||||||
bool g_got_privileged_process_status = false;
|
bool g_got_privileged_process_status = false;
|
||||||
u64 g_min_initial_process_id = 0, g_max_initial_process_id = 0;
|
u64 g_min_initial_process_id = 0, g_max_initial_process_id = 0;
|
||||||
u64 g_cur_process_id = 0;
|
u64 g_cur_process_id = 0;
|
||||||
@ -69,7 +69,7 @@ namespace sts::cfg {
|
|||||||
|
|
||||||
/* Privileged Process utilities. */
|
/* Privileged Process utilities. */
|
||||||
bool IsInitialProcess() {
|
bool IsInitialProcess() {
|
||||||
std::scoped_lock<HosMutex> lk(g_lock);
|
std::scoped_lock lk(g_lock);
|
||||||
|
|
||||||
/* If we've not detected, do detection. */
|
/* If we've not detected, do detection. */
|
||||||
if (!g_got_privileged_process_status) {
|
if (!g_got_privileged_process_status) {
|
||||||
@ -81,7 +81,7 @@ namespace sts::cfg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GetInitialProcessRange(u64 *out_min, u64 *out_max) {
|
void GetInitialProcessRange(u64 *out_min, u64 *out_max) {
|
||||||
std::scoped_lock<HosMutex> lk(g_lock);
|
std::scoped_lock lk(g_lock);
|
||||||
|
|
||||||
/* If we've not detected, do detection. */
|
/* If we've not detected, do detection. */
|
||||||
if (!g_got_privileged_process_status) {
|
if (!g_got_privileged_process_status) {
|
||||||
|
@ -33,7 +33,7 @@ namespace sts::cfg {
|
|||||||
constexpr size_t NumRequiredServicesForSdCardAccess = util::size(RequiredServicesForSdCardAccess);
|
constexpr size_t NumRequiredServicesForSdCardAccess = util::size(RequiredServicesForSdCardAccess);
|
||||||
|
|
||||||
/* SD card globals. */
|
/* SD card globals. */
|
||||||
HosMutex g_sd_card_lock;
|
os::Mutex g_sd_card_lock;
|
||||||
bool g_sd_card_initialized = false;
|
bool g_sd_card_initialized = false;
|
||||||
FsFileSystem g_sd_card_filesystem = {};
|
FsFileSystem g_sd_card_filesystem = {};
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ namespace sts::cfg {
|
|||||||
|
|
||||||
/* SD card utilities. */
|
/* SD card utilities. */
|
||||||
bool IsSdCardInitialized() {
|
bool IsSdCardInitialized() {
|
||||||
std::scoped_lock<HosMutex> lk(g_sd_card_lock);
|
std::scoped_lock lk(g_sd_card_lock);
|
||||||
|
|
||||||
if (!g_sd_card_initialized) {
|
if (!g_sd_card_initialized) {
|
||||||
if (R_SUCCEEDED(TryInitializeSdCard())) {
|
if (R_SUCCEEDED(TryInitializeSdCard())) {
|
||||||
@ -75,7 +75,7 @@ namespace sts::cfg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WaitSdCardInitialized() {
|
void WaitSdCardInitialized() {
|
||||||
std::scoped_lock<HosMutex> lk(g_sd_card_lock);
|
std::scoped_lock lk(g_sd_card_lock);
|
||||||
|
|
||||||
InitializeSdCard();
|
InitializeSdCard();
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ namespace sts::hid {
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
/* Global lock. */
|
/* Global lock. */
|
||||||
HosMutex g_hid_lock;
|
os::Mutex g_hid_lock;
|
||||||
bool g_initialized_hid = false;
|
bool g_initialized_hid = false;
|
||||||
|
|
||||||
/* Helper. */
|
/* Helper. */
|
||||||
@ -53,7 +53,7 @@ namespace sts::hid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result GetKeysHeld(u64 *out) {
|
Result GetKeysHeld(u64 *out) {
|
||||||
std::scoped_lock<HosMutex> lk(g_hid_lock);
|
std::scoped_lock lk(g_hid_lock);
|
||||||
|
|
||||||
R_TRY(EnsureHidInitialized());
|
R_TRY(EnsureHidInitialized());
|
||||||
|
|
||||||
|
@ -1,235 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms and conditions of the GNU General Public License,
|
|
||||||
* version 2, as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <mutex>
|
|
||||||
#include <switch.h>
|
|
||||||
#include <stratosphere.hpp>
|
|
||||||
|
|
||||||
|
|
||||||
void HosMessageQueue::Send(uintptr_t data) {
|
|
||||||
/* Acquire mutex, wait sendable. */
|
|
||||||
std::scoped_lock<HosMutex> lock(this->queue_lock);
|
|
||||||
|
|
||||||
while (this->IsFull()) {
|
|
||||||
this->cv_not_full.Wait(&this->queue_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send, signal. */
|
|
||||||
this->SendInternal(data);
|
|
||||||
this->cv_not_empty.WakeAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HosMessageQueue::TrySend(uintptr_t data) {
|
|
||||||
std::scoped_lock<HosMutex> lock(this->queue_lock);
|
|
||||||
if (this->IsFull()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send, signal. */
|
|
||||||
this->SendInternal(data);
|
|
||||||
this->cv_not_empty.WakeAll();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HosMessageQueue::TimedSend(uintptr_t data, u64 timeout) {
|
|
||||||
std::scoped_lock<HosMutex> lock(this->queue_lock);
|
|
||||||
TimeoutHelper timeout_helper(timeout);
|
|
||||||
|
|
||||||
while (this->IsFull()) {
|
|
||||||
if (timeout_helper.TimedOut()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->cv_not_full.TimedWait(timeout, &this->queue_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send, signal. */
|
|
||||||
this->SendInternal(data);
|
|
||||||
this->cv_not_empty.WakeAll();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HosMessageQueue::SendNext(uintptr_t data) {
|
|
||||||
/* Acquire mutex, wait sendable. */
|
|
||||||
std::scoped_lock<HosMutex> lock(this->queue_lock);
|
|
||||||
|
|
||||||
while (this->IsFull()) {
|
|
||||||
this->cv_not_full.Wait(&this->queue_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send, signal. */
|
|
||||||
this->SendNextInternal(data);
|
|
||||||
this->cv_not_empty.WakeAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HosMessageQueue::TrySendNext(uintptr_t data) {
|
|
||||||
std::scoped_lock<HosMutex> lock(this->queue_lock);
|
|
||||||
if (this->IsFull()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send, signal. */
|
|
||||||
this->SendNextInternal(data);
|
|
||||||
this->cv_not_empty.WakeAll();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HosMessageQueue::TimedSendNext(uintptr_t data, u64 timeout) {
|
|
||||||
std::scoped_lock<HosMutex> lock(this->queue_lock);
|
|
||||||
TimeoutHelper timeout_helper(timeout);
|
|
||||||
|
|
||||||
while (this->IsFull()) {
|
|
||||||
if (timeout_helper.TimedOut()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->cv_not_full.TimedWait(timeout, &this->queue_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send, signal. */
|
|
||||||
this->SendNextInternal(data);
|
|
||||||
this->cv_not_empty.WakeAll();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HosMessageQueue::Receive(uintptr_t *out) {
|
|
||||||
/* Acquire mutex, wait receivable. */
|
|
||||||
std::scoped_lock<HosMutex> lock(this->queue_lock);
|
|
||||||
|
|
||||||
while (this->IsEmpty()) {
|
|
||||||
this->cv_not_empty.Wait(&this->queue_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Receive, signal. */
|
|
||||||
*out = this->ReceiveInternal();
|
|
||||||
this->cv_not_full.WakeAll();
|
|
||||||
}
|
|
||||||
bool HosMessageQueue::TryReceive(uintptr_t *out) {
|
|
||||||
/* Acquire mutex, wait receivable. */
|
|
||||||
std::scoped_lock<HosMutex> lock(this->queue_lock);
|
|
||||||
|
|
||||||
if (this->IsEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Receive, signal. */
|
|
||||||
*out = this->ReceiveInternal();
|
|
||||||
this->cv_not_full.WakeAll();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HosMessageQueue::TimedReceive(uintptr_t *out, u64 timeout) {
|
|
||||||
std::scoped_lock<HosMutex> lock(this->queue_lock);
|
|
||||||
TimeoutHelper timeout_helper(timeout);
|
|
||||||
|
|
||||||
while (this->IsEmpty()) {
|
|
||||||
if (timeout_helper.TimedOut()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->cv_not_empty.TimedWait(timeout, &this->queue_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Receive, signal. */
|
|
||||||
*out = this->ReceiveInternal();
|
|
||||||
this->cv_not_full.WakeAll();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HosMessageQueue::Peek(uintptr_t *out) {
|
|
||||||
/* Acquire mutex, wait receivable. */
|
|
||||||
std::scoped_lock<HosMutex> lock(this->queue_lock);
|
|
||||||
|
|
||||||
while (this->IsEmpty()) {
|
|
||||||
this->cv_not_empty.Wait(&this->queue_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Peek. */
|
|
||||||
*out = this->PeekInternal();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HosMessageQueue::TryPeek(uintptr_t *out) {
|
|
||||||
/* Acquire mutex, wait receivable. */
|
|
||||||
std::scoped_lock<HosMutex> lock(this->queue_lock);
|
|
||||||
|
|
||||||
if (this->IsEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Peek. */
|
|
||||||
*out = this->PeekInternal();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HosMessageQueue::TimedPeek(uintptr_t *out, u64 timeout) {
|
|
||||||
std::scoped_lock<HosMutex> lock(this->queue_lock);
|
|
||||||
TimeoutHelper timeout_helper(timeout);
|
|
||||||
|
|
||||||
while (this->IsEmpty()) {
|
|
||||||
if (timeout_helper.TimedOut()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->cv_not_empty.TimedWait(timeout, &this->queue_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Peek. */
|
|
||||||
*out = this->PeekInternal();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HosMessageQueue::SendInternal(uintptr_t data) {
|
|
||||||
/* Ensure we don't corrupt the queue, but this should never happen. */
|
|
||||||
if (this->count >= this->capacity) {
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write data to tail of queue. */
|
|
||||||
this->buffer[(this->count++ + this->offset) % this->capacity] = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HosMessageQueue::SendNextInternal(uintptr_t data) {
|
|
||||||
/* Ensure we don't corrupt the queue, but this should never happen. */
|
|
||||||
if (this->count >= this->capacity) {
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write data to head of queue. */
|
|
||||||
this->offset = (this->offset + this->capacity - 1) % this->capacity;
|
|
||||||
this->buffer[this->offset] = data;
|
|
||||||
this->count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t HosMessageQueue::ReceiveInternal() {
|
|
||||||
/* Ensure we don't corrupt the queue, but this should never happen. */
|
|
||||||
if (this->count == 0) {
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t data = this->buffer[this->offset];
|
|
||||||
this->offset = (this->offset + 1) % this->capacity;
|
|
||||||
this->count--;
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t HosMessageQueue::PeekInternal() {
|
|
||||||
/* Ensure we don't corrupt the queue, but this should never happen. */
|
|
||||||
if (this->count == 0) {
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->buffer[this->offset];
|
|
||||||
}
|
|
@ -18,8 +18,8 @@
|
|||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
static HosMutex g_server_query_mutex;
|
static sts::os::Mutex g_server_query_mutex;
|
||||||
static HosThread g_server_query_manager_thread;
|
static sts::os::Thread g_server_query_manager_thread;
|
||||||
static SessionManagerBase *g_server_query_manager = nullptr;
|
static SessionManagerBase *g_server_query_manager = nullptr;
|
||||||
|
|
||||||
static void ServerQueryManagerThreadFunc(void *arg) {
|
static void ServerQueryManagerThreadFunc(void *arg) {
|
||||||
@ -27,7 +27,7 @@ static void ServerQueryManagerThreadFunc(void *arg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RegisterMitmServerQueryHandle(Handle query_h, ServiceObjectHolder &&service) {
|
void RegisterMitmServerQueryHandle(Handle query_h, ServiceObjectHolder &&service) {
|
||||||
std::scoped_lock<HosMutex> lock(g_server_query_mutex);
|
std::scoped_lock lock(g_server_query_mutex);
|
||||||
|
|
||||||
const bool exists = g_server_query_manager != nullptr;
|
const bool exists = g_server_query_manager != nullptr;
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
|
235
source/os/os_message_queue.cpp
Normal file
235
source/os/os_message_queue.cpp
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace sts::os {
|
||||||
|
|
||||||
|
void MessageQueue::SendInternal(uintptr_t data) {
|
||||||
|
/* Ensure we don't corrupt the queue, but this should never happen. */
|
||||||
|
if (this->count >= this->capacity) {
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write data to tail of queue. */
|
||||||
|
this->buffer[(this->count++ + this->offset) % this->capacity] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageQueue::SendNextInternal(uintptr_t data) {
|
||||||
|
/* Ensure we don't corrupt the queue, but this should never happen. */
|
||||||
|
if (this->count >= this->capacity) {
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write data to head of queue. */
|
||||||
|
this->offset = (this->offset + this->capacity - 1) % this->capacity;
|
||||||
|
this->buffer[this->offset] = data;
|
||||||
|
this->count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t MessageQueue::ReceiveInternal() {
|
||||||
|
/* Ensure we don't corrupt the queue, but this should never happen. */
|
||||||
|
if (this->count == 0) {
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t data = this->buffer[this->offset];
|
||||||
|
this->offset = (this->offset + 1) % this->capacity;
|
||||||
|
this->count--;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t MessageQueue::PeekInternal() {
|
||||||
|
/* Ensure we don't corrupt the queue, but this should never happen. */
|
||||||
|
if (this->count == 0) {
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this->buffer[this->offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageQueue::Send(uintptr_t data) {
|
||||||
|
/* Acquire mutex, wait sendable. */
|
||||||
|
std::scoped_lock lock(this->queue_lock);
|
||||||
|
|
||||||
|
while (this->IsFull()) {
|
||||||
|
this->cv_not_full.Wait(&this->queue_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send, signal. */
|
||||||
|
this->SendInternal(data);
|
||||||
|
this->cv_not_empty.WakeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MessageQueue::TrySend(uintptr_t data) {
|
||||||
|
std::scoped_lock lock(this->queue_lock);
|
||||||
|
if (this->IsFull()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send, signal. */
|
||||||
|
this->SendInternal(data);
|
||||||
|
this->cv_not_empty.WakeAll();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MessageQueue::TimedSend(uintptr_t data, u64 timeout) {
|
||||||
|
std::scoped_lock lock(this->queue_lock);
|
||||||
|
TimeoutHelper timeout_helper(timeout);
|
||||||
|
|
||||||
|
while (this->IsFull()) {
|
||||||
|
if (timeout_helper.TimedOut()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->cv_not_full.TimedWait(&this->queue_lock, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send, signal. */
|
||||||
|
this->SendInternal(data);
|
||||||
|
this->cv_not_empty.WakeAll();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageQueue::SendNext(uintptr_t data) {
|
||||||
|
/* Acquire mutex, wait sendable. */
|
||||||
|
std::scoped_lock lock(this->queue_lock);
|
||||||
|
|
||||||
|
while (this->IsFull()) {
|
||||||
|
this->cv_not_full.Wait(&this->queue_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send, signal. */
|
||||||
|
this->SendNextInternal(data);
|
||||||
|
this->cv_not_empty.WakeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MessageQueue::TrySendNext(uintptr_t data) {
|
||||||
|
std::scoped_lock lock(this->queue_lock);
|
||||||
|
if (this->IsFull()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send, signal. */
|
||||||
|
this->SendNextInternal(data);
|
||||||
|
this->cv_not_empty.WakeAll();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MessageQueue::TimedSendNext(uintptr_t data, u64 timeout) {
|
||||||
|
std::scoped_lock lock(this->queue_lock);
|
||||||
|
TimeoutHelper timeout_helper(timeout);
|
||||||
|
|
||||||
|
while (this->IsFull()) {
|
||||||
|
if (timeout_helper.TimedOut()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->cv_not_full.TimedWait(&this->queue_lock, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send, signal. */
|
||||||
|
this->SendNextInternal(data);
|
||||||
|
this->cv_not_empty.WakeAll();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageQueue::Receive(uintptr_t *out) {
|
||||||
|
/* Acquire mutex, wait receivable. */
|
||||||
|
std::scoped_lock lock(this->queue_lock);
|
||||||
|
|
||||||
|
while (this->IsEmpty()) {
|
||||||
|
this->cv_not_empty.Wait(&this->queue_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Receive, signal. */
|
||||||
|
*out = this->ReceiveInternal();
|
||||||
|
this->cv_not_full.WakeAll();
|
||||||
|
}
|
||||||
|
bool MessageQueue::TryReceive(uintptr_t *out) {
|
||||||
|
/* Acquire mutex, wait receivable. */
|
||||||
|
std::scoped_lock lock(this->queue_lock);
|
||||||
|
|
||||||
|
if (this->IsEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Receive, signal. */
|
||||||
|
*out = this->ReceiveInternal();
|
||||||
|
this->cv_not_full.WakeAll();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MessageQueue::TimedReceive(uintptr_t *out, u64 timeout) {
|
||||||
|
std::scoped_lock lock(this->queue_lock);
|
||||||
|
TimeoutHelper timeout_helper(timeout);
|
||||||
|
|
||||||
|
while (this->IsEmpty()) {
|
||||||
|
if (timeout_helper.TimedOut()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->cv_not_empty.TimedWait(&this->queue_lock, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Receive, signal. */
|
||||||
|
*out = this->ReceiveInternal();
|
||||||
|
this->cv_not_full.WakeAll();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageQueue::Peek(uintptr_t *out) {
|
||||||
|
/* Acquire mutex, wait receivable. */
|
||||||
|
std::scoped_lock lock(this->queue_lock);
|
||||||
|
|
||||||
|
while (this->IsEmpty()) {
|
||||||
|
this->cv_not_empty.Wait(&this->queue_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Peek. */
|
||||||
|
*out = this->PeekInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MessageQueue::TryPeek(uintptr_t *out) {
|
||||||
|
/* Acquire mutex, wait receivable. */
|
||||||
|
std::scoped_lock lock(this->queue_lock);
|
||||||
|
|
||||||
|
if (this->IsEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Peek. */
|
||||||
|
*out = this->PeekInternal();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MessageQueue::TimedPeek(uintptr_t *out, u64 timeout) {
|
||||||
|
std::scoped_lock lock(this->queue_lock);
|
||||||
|
TimeoutHelper timeout_helper(timeout);
|
||||||
|
|
||||||
|
while (this->IsEmpty()) {
|
||||||
|
if (timeout_helper.TimedOut()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->cv_not_empty.TimedWait(&this->queue_lock, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Peek. */
|
||||||
|
*out = this->PeekInternal();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -25,26 +25,26 @@ namespace sts::pm::info {
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
/* Global lock. */
|
/* Global lock. */
|
||||||
HosMutex g_info_lock;
|
os::Mutex g_info_lock;
|
||||||
std::set<u64> g_cached_launched_titles;
|
std::set<u64> g_cached_launched_titles;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Information API. */
|
/* Information API. */
|
||||||
Result GetTitleId(ncm::TitleId *out_title_id, u64 process_id) {
|
Result GetTitleId(ncm::TitleId *out_title_id, u64 process_id) {
|
||||||
std::scoped_lock<HosMutex> lk(g_info_lock);
|
std::scoped_lock lk(g_info_lock);
|
||||||
|
|
||||||
return pminfoGetTitleId(reinterpret_cast<u64 *>(out_title_id), process_id);
|
return pminfoGetTitleId(reinterpret_cast<u64 *>(out_title_id), process_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetProcessId(u64 *out_process_id, ncm::TitleId title_id) {
|
Result GetProcessId(u64 *out_process_id, ncm::TitleId title_id) {
|
||||||
std::scoped_lock<HosMutex> lk(g_info_lock);
|
std::scoped_lock lk(g_info_lock);
|
||||||
|
|
||||||
return pminfoAtmosphereGetProcessId(out_process_id, static_cast<u64>(title_id));
|
return pminfoAtmosphereGetProcessId(out_process_id, static_cast<u64>(title_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result WEAK HasLaunchedTitle(bool *out, ncm::TitleId title_id) {
|
Result WEAK HasLaunchedTitle(bool *out, ncm::TitleId title_id) {
|
||||||
std::scoped_lock<HosMutex> lk(g_info_lock);
|
std::scoped_lock lk(g_info_lock);
|
||||||
|
|
||||||
if (g_cached_launched_titles.find(static_cast<u64>(title_id)) != g_cached_launched_titles.end()) {
|
if (g_cached_launched_titles.find(static_cast<u64>(title_id)) != g_cached_launched_titles.end()) {
|
||||||
*out = true;
|
*out = true;
|
||||||
|
@ -21,17 +21,17 @@ namespace sts::sm::impl {
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
/* Globals. */
|
/* Globals. */
|
||||||
HosRecursiveMutex g_user_session_mutex;
|
os::RecursiveMutex g_user_session_mutex;
|
||||||
HosRecursiveMutex g_mitm_session_mutex;
|
os::RecursiveMutex g_mitm_session_mutex;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Utilities. */
|
/* Utilities. */
|
||||||
HosRecursiveMutex &GetUserSessionMutex() {
|
os::RecursiveMutex &GetUserSessionMutex() {
|
||||||
return g_user_session_mutex;
|
return g_user_session_mutex;
|
||||||
}
|
}
|
||||||
|
|
||||||
HosRecursiveMutex &GetMitmSessionMutex() {
|
os::RecursiveMutex &GetMitmSessionMutex() {
|
||||||
return g_mitm_session_mutex;
|
return g_mitm_session_mutex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,12 +25,12 @@
|
|||||||
namespace sts::sm::impl {
|
namespace sts::sm::impl {
|
||||||
|
|
||||||
/* Utilities. */
|
/* Utilities. */
|
||||||
HosRecursiveMutex &GetUserSessionMutex();
|
os::RecursiveMutex &GetUserSessionMutex();
|
||||||
HosRecursiveMutex &GetMitmSessionMutex();
|
os::RecursiveMutex &GetMitmSessionMutex();
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
Result DoWithUserSession(F f) {
|
Result DoWithUserSession(F f) {
|
||||||
std::scoped_lock<HosRecursiveMutex &> lk(GetUserSessionMutex());
|
std::scoped_lock<os::RecursiveMutex &> lk(GetUserSessionMutex());
|
||||||
{
|
{
|
||||||
R_ASSERT(smInitialize());
|
R_ASSERT(smInitialize());
|
||||||
ON_SCOPE_EXIT { smExit(); };
|
ON_SCOPE_EXIT { smExit(); };
|
||||||
@ -41,7 +41,7 @@ namespace sts::sm::impl {
|
|||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
Result DoWithMitmSession(F f) {
|
Result DoWithMitmSession(F f) {
|
||||||
std::scoped_lock<HosRecursiveMutex &> lk(GetMitmSessionMutex());
|
std::scoped_lock<os::RecursiveMutex &> lk(GetMitmSessionMutex());
|
||||||
{
|
{
|
||||||
R_ASSERT(smAtmosphereMitmInitialize());
|
R_ASSERT(smAtmosphereMitmInitialize());
|
||||||
ON_SCOPE_EXIT { smAtmosphereMitmExit(); };
|
ON_SCOPE_EXIT { smAtmosphereMitmExit(); };
|
||||||
|
@ -17,14 +17,8 @@
|
|||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
static HosRecursiveMutex g_sm_session_lock;
|
static sts::os::RecursiveMutex g_sm_session_lock;
|
||||||
static HosRecursiveMutex g_sm_mitm_session_lock;
|
|
||||||
|
|
||||||
|
sts::os::RecursiveMutex &GetSmSessionMutex() {
|
||||||
HosRecursiveMutex &GetSmSessionMutex() {
|
|
||||||
return g_sm_session_lock;
|
return g_sm_session_lock;
|
||||||
}
|
}
|
||||||
|
|
||||||
HosRecursiveMutex &GetSmMitmSessionMutex() {
|
|
||||||
return g_sm_mitm_session_lock;
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user