ams: support building unit test programs on windows/linux/macos
This commit is contained in:
@@ -19,6 +19,8 @@
|
||||
|
||||
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||
#include <stratosphere/os/impl/os_internal_busy_mutex_impl.os.horizon.hpp>
|
||||
#elif defined(ATMOSPHERE_OS_WINDOWS) || defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS)
|
||||
#include <stratosphere/os/impl/os_internal_busy_mutex_impl.os.generic.hpp>
|
||||
#else
|
||||
#error "Unknown OS for ams::os::impl::InternalBusyMutexImpl"
|
||||
#endif
|
||||
@@ -31,10 +33,10 @@ namespace ams::os::impl {
|
||||
public:
|
||||
constexpr InternalBusyMutex() : m_impl() { /* ... */ }
|
||||
|
||||
constexpr void Initialize() { m_impl.Initialize(); }
|
||||
constexpr void Finalize() { m_impl.Finalize(); }
|
||||
ALWAYS_INLINE void Initialize() { m_impl.Initialize(); }
|
||||
ALWAYS_INLINE void Finalize() { m_impl.Finalize(); }
|
||||
|
||||
bool IsLocked() const { return m_impl.IsLocked(); }
|
||||
ALWAYS_INLINE bool IsLocked() const { return m_impl.IsLocked(); }
|
||||
|
||||
ALWAYS_INLINE void Lock() { return m_impl.Lock(); }
|
||||
ALWAYS_INLINE bool TryLock() { return m_impl.TryLock(); }
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 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 <vapours.hpp>
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
|
||||
class InternalBusyMutexImpl {
|
||||
private:
|
||||
std::atomic<bool> m_value{false};
|
||||
u8 m_padding[3]{};
|
||||
public:
|
||||
constexpr InternalBusyMutexImpl() = default;
|
||||
|
||||
ALWAYS_INLINE void Initialize() { m_value.store(false, std::memory_order_relaxed); }
|
||||
|
||||
ALWAYS_INLINE void Finalize() { /* ... */ }
|
||||
|
||||
ALWAYS_INLINE bool IsLocked() const { return m_value.load(std::memory_order_acquire); }
|
||||
|
||||
ALWAYS_INLINE bool TryLock() {
|
||||
bool expected = false;
|
||||
return m_value.compare_exchange_weak(expected, true, std::memory_order_acquire, std::memory_order_acquire);
|
||||
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void Lock() {
|
||||
while (!this->TryLock()) {
|
||||
#if defined(ATMOSPHERE_ARCH_X64) || defined(ATMOSPHERE_ARCH_X86)
|
||||
_mm_pause();
|
||||
#elif defined(ATMOSPHERE_ARCH_ARM64) || defined(ATMOSPHERE_ARCH_ARM)
|
||||
__asm__ __volatile__("yield" ::: "memory");
|
||||
#else
|
||||
#error "InternalBusyMutex requires yield intrinsics"
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void Unlock() {
|
||||
m_value.store(false, std::memory_order_release);
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(InternalBusyMutexImpl) == sizeof(u32));
|
||||
|
||||
#define AMS_OS_INTERNAL_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZE_ARRAY_VALUES 0
|
||||
|
||||
}
|
||||
@@ -35,4 +35,6 @@ namespace ams::os::impl {
|
||||
void Unlock();
|
||||
};
|
||||
|
||||
#define AMS_OS_INTERNAL_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZE_ARRAY_VALUES 0
|
||||
|
||||
}
|
||||
|
||||
@@ -18,8 +18,12 @@
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/os/os_condition_variable_common.hpp>
|
||||
|
||||
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||
#if defined(AMS_OS_IMPL_USE_PTHREADS)
|
||||
#include <stratosphere/os/impl/os_internal_condition_variable_impl.pthread.hpp>
|
||||
#elif defined(ATMOSPHERE_OS_HORIZON)
|
||||
#include <stratosphere/os/impl/os_internal_condition_variable_impl.os.horizon.hpp>
|
||||
#elif defined(ATMOSPHERE_OS_WINDOWS)
|
||||
#include <stratosphere/os/impl/os_internal_condition_variable_impl.os.windows.hpp>
|
||||
#else
|
||||
#error "Unknown OS for ams::os::impl::InternalConditionVariableImpl"
|
||||
#endif
|
||||
@@ -32,10 +36,14 @@ namespace ams::os::impl {
|
||||
public:
|
||||
constexpr InternalConditionVariable() : m_impl() { /* ... */ }
|
||||
|
||||
constexpr void Initialize() {
|
||||
void Initialize() {
|
||||
m_impl.Initialize();
|
||||
}
|
||||
|
||||
void Finalize() {
|
||||
m_impl.Finalize();
|
||||
}
|
||||
|
||||
void Signal() {
|
||||
m_impl.Signal();
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace ams::os::impl {
|
||||
constexpr void Initialize() {
|
||||
m_value = 0;
|
||||
}
|
||||
constexpr void Finalize() { /* ... */ }
|
||||
|
||||
void Signal();
|
||||
void Broadcast();
|
||||
@@ -40,4 +41,8 @@ namespace ams::os::impl {
|
||||
ConditionVariableStatus TimedWait(InternalCriticalSection *cs, const TimeoutHelper &timeout_helper);
|
||||
};
|
||||
|
||||
using InternalConditionVariableStorageTypeForConstantInitialize = u32;
|
||||
|
||||
#define AMS_OS_INTERNAL_CONDITION_VARIABLE_IMPL_CONSTANT_INITIALIZER {0}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 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 <vapours.hpp>
|
||||
#include <stratosphere/os/os_condition_variable_common.hpp>
|
||||
#include <stratosphere/os/impl/os_internal_critical_section.hpp>
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
class TimeoutHelper;
|
||||
|
||||
struct WindowsConditionVariable;
|
||||
|
||||
using WindowsConditionVariableStorage = util::TypedStorage<WindowsConditionVariable, sizeof(void *), alignof(void *)>;
|
||||
|
||||
#if defined(ATMOSPHERE_ARCH_X64)
|
||||
#define AMS_OS_WINDOWS_CONDITION_VARIABLE_CONSTANT_INITIALIZE_ARRAY_VALUES 0, 0
|
||||
#elif defined(ATMOSPHERE_ARCH_X86)
|
||||
#define AMS_OS_WINDOWS_CONDITION_VARIABLE_CONSTANT_INITIALIZE_ARRAY_VALUES 0
|
||||
#else
|
||||
#error "Unknown architecture for WindowsConditionVariable initializer"
|
||||
#endif
|
||||
|
||||
class InternalConditionVariableImpl {
|
||||
private:
|
||||
u32 m_value;
|
||||
public:
|
||||
union {
|
||||
s32 _arr[sizeof(WindowsConditionVariableStorage) / sizeof(s32)];
|
||||
WindowsConditionVariableStorage m_windows_cv_storage;
|
||||
};
|
||||
constexpr InternalConditionVariableImpl() : _arr{AMS_OS_WINDOWS_CONDITION_VARIABLE_CONSTANT_INITIALIZE_ARRAY_VALUES} { /* ... */ }
|
||||
constexpr ~InternalConditionVariableImpl() {
|
||||
if (!std::is_constant_evaluated()) {
|
||||
this->Finalize();
|
||||
}
|
||||
}
|
||||
|
||||
void Initialize();
|
||||
void Finalize();
|
||||
|
||||
void Signal();
|
||||
void Broadcast();
|
||||
|
||||
void Wait(InternalCriticalSection *cs);
|
||||
ConditionVariableStatus TimedWait(InternalCriticalSection *cs, const TimeoutHelper &timeout_helper);
|
||||
};
|
||||
|
||||
struct InternalConditionVariableStorageTypeForConstantInitialize { s32 _arr[sizeof(WindowsConditionVariableStorage) / sizeof(s32)]; };
|
||||
|
||||
#define AMS_OS_INTERNAL_CONDITION_VARIABLE_IMPL_CONSTANT_INITIALIZER { AMS_OS_WINDOWS_CONDITION_VARIABLE_CONSTANT_INITIALIZE_ARRAY_VALUES }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 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 <vapours.hpp>
|
||||
#include <stratosphere/os/os_condition_variable_common.hpp>
|
||||
#include <stratosphere/os/impl/os_internal_critical_section.hpp>
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
class TimeoutHelper;
|
||||
|
||||
class InternalConditionVariableImpl {
|
||||
private:
|
||||
pthread_cond_t m_pthread_cond = PTHREAD_COND_INITIALIZER;
|
||||
public:
|
||||
constexpr InternalConditionVariableImpl() = default;
|
||||
|
||||
constexpr ~InternalConditionVariableImpl() {
|
||||
if (!std::is_constant_evaluated()) {
|
||||
this->Finalize();
|
||||
}
|
||||
}
|
||||
|
||||
void Initialize();
|
||||
void Finalize();
|
||||
|
||||
void Signal();
|
||||
void Broadcast();
|
||||
|
||||
void Wait(InternalCriticalSection *cs);
|
||||
ConditionVariableStatus TimedWait(InternalCriticalSection *cs, const TimeoutHelper &timeout_helper);
|
||||
};
|
||||
|
||||
using InternalConditionVariableStorageTypeForConstantInitialize = pthread_cond_t;
|
||||
|
||||
#define AMS_OS_INTERNAL_CONDITION_VARIABLE_IMPL_CONSTANT_INITIALIZER ._storage_for_constant_initialize = PTHREAD_COND_INITIALIZER
|
||||
|
||||
}
|
||||
@@ -17,8 +17,12 @@
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
|
||||
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||
#if defined(AMS_OS_IMPL_USE_PTHREADS)
|
||||
#include <stratosphere/os/impl/os_internal_critical_section_impl.pthread.hpp>
|
||||
#elif defined(ATMOSPHERE_OS_HORIZON)
|
||||
#include <stratosphere/os/impl/os_internal_critical_section_impl.os.horizon.hpp>
|
||||
#elif defined(ATMOSPHERE_OS_WINDOWS)
|
||||
#include <stratosphere/os/impl/os_internal_critical_section_impl.os.windows.hpp>
|
||||
#else
|
||||
#error "Unknown OS for ams::os::impl::InternalCriticalSectionImpl"
|
||||
#endif
|
||||
@@ -31,14 +35,16 @@ namespace ams::os::impl {
|
||||
public:
|
||||
constexpr InternalCriticalSection() : m_impl() { /* ... */ }
|
||||
|
||||
constexpr void Initialize() { m_impl.Initialize(); }
|
||||
constexpr void Finalize() { m_impl.Finalize(); }
|
||||
void Initialize() { m_impl.Initialize(); }
|
||||
void Finalize() { m_impl.Finalize(); }
|
||||
|
||||
void Enter() { return m_impl.Enter(); }
|
||||
bool TryEnter() { return m_impl.TryEnter(); }
|
||||
void Leave() { return m_impl.Leave(); }
|
||||
|
||||
#if defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD)
|
||||
bool IsLockedByCurrentThread() const { return m_impl.IsLockedByCurrentThread(); }
|
||||
#endif
|
||||
|
||||
ALWAYS_INLINE void Lock() { return this->Enter(); }
|
||||
ALWAYS_INLINE bool TryLock() { return this->TryEnter(); }
|
||||
|
||||
@@ -55,4 +55,10 @@ namespace ams::os::impl {
|
||||
ALWAYS_INLINE void unlock() { return this->Unlock(); }
|
||||
};
|
||||
|
||||
using InternalCriticalSectionStorageTypeForConstantInitialize = u32;
|
||||
|
||||
#define AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER {0}
|
||||
|
||||
#define AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 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 <vapours.hpp>
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
class InternalConditionVariableImpl;
|
||||
|
||||
struct WindowsCriticalSection;
|
||||
|
||||
using WindowsCriticalSectionStorage = util::TypedStorage<WindowsCriticalSection, 8 + 4 * sizeof(void *), alignof(void *)>;
|
||||
|
||||
#if defined(ATMOSPHERE_ARCH_X64)
|
||||
#define AMS_OS_WINDOWS_CRITICAL_SECTION_CONSTANT_INITIALIZE_ARRAY_VALUES -1, -1, -1, 0, 0, 0, 0, 0, 0, 0
|
||||
#elif defined(ATMOSPHERE_ARCH_X86)
|
||||
#define AMS_OS_WINDOWS_CRITICAL_SECTION_CONSTANT_INITIALIZE_ARRAY_VALUES -1, -1, 0, 0, 0, 0
|
||||
#else
|
||||
#error "Unknown architecture for WindowsCriticalSection initializer"
|
||||
#endif
|
||||
|
||||
class InternalCriticalSectionImpl {
|
||||
private:
|
||||
friend class InternalConditionVariableImpl;
|
||||
private:
|
||||
union {
|
||||
s32 _arr[sizeof(WindowsCriticalSectionStorage) / sizeof(s32)];
|
||||
WindowsCriticalSectionStorage m_windows_critical_section_storage;
|
||||
};
|
||||
public:
|
||||
constexpr InternalCriticalSectionImpl() : _arr{AMS_OS_WINDOWS_CRITICAL_SECTION_CONSTANT_INITIALIZE_ARRAY_VALUES} { /* ... */ }
|
||||
constexpr ~InternalCriticalSectionImpl() {
|
||||
if (!std::is_constant_evaluated()) {
|
||||
this->Finalize();
|
||||
}
|
||||
}
|
||||
|
||||
void Initialize();
|
||||
void Finalize();
|
||||
|
||||
void Enter();
|
||||
bool TryEnter();
|
||||
void Leave();
|
||||
|
||||
bool IsLockedByCurrentThread() const;
|
||||
|
||||
ALWAYS_INLINE void Lock() { return this->Enter(); }
|
||||
ALWAYS_INLINE bool TryLock() { return this->TryEnter(); }
|
||||
ALWAYS_INLINE void Unlock() { return this->Leave(); }
|
||||
|
||||
ALWAYS_INLINE void lock() { return this->Lock(); }
|
||||
ALWAYS_INLINE bool try_lock() { return this->TryLock(); }
|
||||
ALWAYS_INLINE void unlock() { return this->Unlock(); }
|
||||
};
|
||||
|
||||
struct InternalCriticalSectionStorageTypeForConstantInitialize { s32 _arr[sizeof(WindowsCriticalSectionStorage) / sizeof(s32)]; };
|
||||
|
||||
#define AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER { AMS_OS_WINDOWS_CRITICAL_SECTION_CONSTANT_INITIALIZE_ARRAY_VALUES }
|
||||
|
||||
#define AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 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 <vapours.hpp>
|
||||
#include <stratosphere/os/os_common_types.hpp>
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
class InternalConditionVariableImpl;
|
||||
|
||||
/* NOTE: macOS (and possibly other targets) do not provide adaptive mutex. */
|
||||
#if defined(PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP)
|
||||
#define AMS_OS_IMPL_PTHREAD_MUTEX_INITIALIZER PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
|
||||
#else
|
||||
#define AMS_OS_IMPL_PTHREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
|
||||
#endif
|
||||
|
||||
#if defined(ATMOSPHERE_OS_LINUX)
|
||||
#define AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD
|
||||
#else
|
||||
//#define AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD
|
||||
#endif
|
||||
|
||||
class InternalCriticalSectionImpl {
|
||||
private:
|
||||
friend class InternalConditionVariableImpl;
|
||||
private:
|
||||
pthread_mutex_t m_pthread_mutex = AMS_OS_IMPL_PTHREAD_MUTEX_INITIALIZER;
|
||||
public:
|
||||
constexpr InternalCriticalSectionImpl() = default;
|
||||
constexpr ~InternalCriticalSectionImpl() {
|
||||
if (!std::is_constant_evaluated()) {
|
||||
this->Finalize();
|
||||
}
|
||||
}
|
||||
|
||||
void Initialize();
|
||||
void Finalize();
|
||||
|
||||
void Enter();
|
||||
bool TryEnter();
|
||||
void Leave();
|
||||
|
||||
#if defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD)
|
||||
bool IsLockedByCurrentThread() const;
|
||||
#endif
|
||||
|
||||
ALWAYS_INLINE void Lock() { return this->Enter(); }
|
||||
ALWAYS_INLINE bool TryLock() { return this->TryEnter(); }
|
||||
ALWAYS_INLINE void Unlock() { return this->Leave(); }
|
||||
|
||||
ALWAYS_INLINE void lock() { return this->Lock(); }
|
||||
ALWAYS_INLINE bool try_lock() { return this->TryLock(); }
|
||||
ALWAYS_INLINE void unlock() { return this->Unlock(); }
|
||||
};
|
||||
|
||||
using InternalCriticalSectionStorageTypeForConstantInitialize = pthread_mutex_t;
|
||||
|
||||
#define AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER ._storage_for_constant_initialize = AMS_OS_IMPL_PTHREAD_MUTEX_INITIALIZER
|
||||
|
||||
}
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||
#include <stratosphere/os/impl/os_internal_light_event_impl.os.horizon.hpp>
|
||||
#elif defined(ATMOSPHERE_OS_WINDOWS) || defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS)
|
||||
#include <stratosphere/os/impl/os_internal_light_event_impl.os.generic.hpp>
|
||||
#else
|
||||
#error "Unknown OS for ams::os::impl::InternalLightEventImpl"
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 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 <vapours.hpp>
|
||||
#include <stratosphere/os/impl/os_internal_critical_section.hpp>
|
||||
#include <stratosphere/os/impl/os_internal_condition_variable.hpp>
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
class TimeoutHelper;
|
||||
|
||||
class InternalLightEventImpl {
|
||||
private:
|
||||
u16 m_counter_low;
|
||||
u8 m_counter_high;
|
||||
std::atomic<u8> m_signal_state;
|
||||
InternalCriticalSection m_cs;
|
||||
InternalConditionVariable m_cv;
|
||||
public:
|
||||
explicit InternalLightEventImpl(bool signaled) { this->Initialize(signaled); }
|
||||
~InternalLightEventImpl() { this->Finalize(); }
|
||||
|
||||
void Initialize(bool signaled);
|
||||
void Finalize();
|
||||
|
||||
void SignalWithAutoClear();
|
||||
void SignalWithManualClear();
|
||||
|
||||
void Clear();
|
||||
|
||||
void WaitWithAutoClear();
|
||||
void WaitWithManualClear();
|
||||
|
||||
bool TryWaitWithAutoClear();
|
||||
bool TryWaitWithManualClear();
|
||||
|
||||
bool TimedWaitWithAutoClear(const TimeoutHelper &timeout_helper);
|
||||
bool TimedWaitWithManualClear(const TimeoutHelper &timeout_helper);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -19,6 +19,12 @@
|
||||
|
||||
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||
#include <stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.horizon.hpp>
|
||||
#elif defined(ATMOSPHERE_OS_WINDOWS)
|
||||
#include <stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.windows.hpp>
|
||||
#elif defined(ATMOSPHERE_OS_LINUX)
|
||||
#include <stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.linux.hpp>
|
||||
#elif defined(ATMOSPHERE_OS_MACOS)
|
||||
#include <stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.macos.hpp>
|
||||
#else
|
||||
#error "Unknown OS for ams::os::impl::InternalReaderWriterBusyMutexImpl"
|
||||
#endif
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/os/impl/os_internal_rw_busy_mutex_value.hpp>
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
@@ -34,4 +35,6 @@ namespace ams::os::impl {
|
||||
void ReleaseWriteLock();
|
||||
};
|
||||
|
||||
#define AMS_OS_INTERNAL_READER_WRITER_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZER {0}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 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 <vapours.hpp>
|
||||
#include <stratosphere/os/impl/os_internal_rw_busy_mutex_value.hpp>
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
/* NOTE: The current implementation is based on load/linked store conditional, we should figure out how to do this on x64. */
|
||||
|
||||
class InternalReaderWriterBusyMutexImpl {
|
||||
private:
|
||||
u32 m_value;
|
||||
public:
|
||||
constexpr InternalReaderWriterBusyMutexImpl() : m_value(0) { if (!std::is_constant_evaluated()) { AMS_ABORT("TODO: Linux InternalReaderWriterBusyMutexImpl"); } }
|
||||
|
||||
constexpr void Initialize() { m_value = 0; if (!std::is_constant_evaluated()) { AMS_ABORT("TODO: Linux InternalReaderWriterBusyMutexImpl"); } }
|
||||
|
||||
void AcquireReadLock() { AMS_ABORT("TODO: Linux InternalReaderWriterBusyMutexImpl"); }
|
||||
void ReleaseReadLock() { AMS_ABORT("TODO: Linux InternalReaderWriterBusyMutexImpl"); }
|
||||
|
||||
void AcquireWriteLock() { AMS_ABORT("TODO: Linux InternalReaderWriterBusyMutexImpl"); }
|
||||
void ReleaseWriteLock() { AMS_ABORT("TODO: Linux InternalReaderWriterBusyMutexImpl"); }
|
||||
};
|
||||
|
||||
#define AMS_OS_INTERNAL_READER_WRITER_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZER {0}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 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 <vapours.hpp>
|
||||
#include <stratosphere/os/impl/os_internal_rw_busy_mutex_value.hpp>
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
/* NOTE: The current implementation is based on load/linked store conditional, we should figure out how to do this on x64. */
|
||||
|
||||
class InternalReaderWriterBusyMutexImpl {
|
||||
private:
|
||||
u32 m_value;
|
||||
public:
|
||||
constexpr InternalReaderWriterBusyMutexImpl() : m_value(0) { if (!std::is_constant_evaluated()) { AMS_ABORT("TODO: macOS InternalReaderWriterBusyMutexImpl"); } }
|
||||
|
||||
constexpr void Initialize() { m_value = 0; if (!std::is_constant_evaluated()) { AMS_ABORT("TODO: macOS InternalReaderWriterBusyMutexImpl"); } }
|
||||
|
||||
void AcquireReadLock() { AMS_ABORT("TODO: macOS InternalReaderWriterBusyMutexImpl"); }
|
||||
void ReleaseReadLock() { AMS_ABORT("TODO: macOS InternalReaderWriterBusyMutexImpl"); }
|
||||
|
||||
void AcquireWriteLock() { AMS_ABORT("TODO: macOS InternalReaderWriterBusyMutexImpl"); }
|
||||
void ReleaseWriteLock() { AMS_ABORT("TODO: macOS InternalReaderWriterBusyMutexImpl"); }
|
||||
};
|
||||
|
||||
#define AMS_OS_INTERNAL_READER_WRITER_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZER {0}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 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 <vapours.hpp>
|
||||
#include <stratosphere/os/impl/os_internal_rw_busy_mutex_value.hpp>
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
/* NOTE: The current implementation is based on load/linked store conditional, we should figure out how to do this on x64. */
|
||||
/* We could also consider using https://docs.microsoft.com/en-us/windows/win32/sync/slim-reader-writer--srw--locks */
|
||||
|
||||
class InternalReaderWriterBusyMutexImpl {
|
||||
private:
|
||||
u32 m_value;
|
||||
public:
|
||||
constexpr InternalReaderWriterBusyMutexImpl() : m_value(0) { if (!std::is_constant_evaluated()) { AMS_ABORT("TODO: Windows InternalReaderWriterBusyMutexImpl"); } }
|
||||
|
||||
constexpr void Initialize() { m_value = 0; if (!std::is_constant_evaluated()) { AMS_ABORT("TODO: Windows InternalReaderWriterBusyMutexImpl"); } }
|
||||
|
||||
void AcquireReadLock() { AMS_ABORT("TODO: Windows InternalReaderWriterBusyMutexImpl"); }
|
||||
void ReleaseReadLock() { AMS_ABORT("TODO: Windows InternalReaderWriterBusyMutexImpl"); }
|
||||
|
||||
void AcquireWriteLock() { AMS_ABORT("TODO: Windows InternalReaderWriterBusyMutexImpl"); }
|
||||
void ReleaseWriteLock() { AMS_ABORT("TODO: Windows InternalReaderWriterBusyMutexImpl"); }
|
||||
};
|
||||
|
||||
#define AMS_OS_INTERNAL_READER_WRITER_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZER {0}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 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 <vapours.hpp>
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
#if defined(ATMOSPHERE_OS_HORIZON) || defined(ATMOSPHERE_OS_WINDOWS) || defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS)
|
||||
class InternalReaderWriterBusyMutexValue {
|
||||
public:
|
||||
static constexpr inline u8 WriterCountMax = std::numeric_limits<u8>::max();
|
||||
|
||||
static constexpr ALWAYS_INLINE u16 GetReaderCount(u32 v) {
|
||||
return static_cast<u16>(v >> 0);
|
||||
}
|
||||
|
||||
static constexpr ALWAYS_INLINE u8 GetWriterCurrent(u32 v) {
|
||||
return static_cast<u8>(v >> 16);
|
||||
}
|
||||
|
||||
static constexpr ALWAYS_INLINE u8 GetWriterNext(u32 v) {
|
||||
return static_cast<u8>(v >> 24);
|
||||
}
|
||||
|
||||
static constexpr ALWAYS_INLINE u32 IncrementWriterNext(u32 v) {
|
||||
return v + (1u << 24);
|
||||
}
|
||||
|
||||
static constexpr ALWAYS_INLINE bool IsWriteLocked(u32 v) {
|
||||
return GetWriterCurrent(v) != GetWriterNext(v);
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE u8 *GetWriterCurrentPointer(u32 *p) {
|
||||
if constexpr (util::IsLittleEndian()) {
|
||||
return reinterpret_cast<u8 *>(reinterpret_cast<uintptr_t>(p)) + 2;
|
||||
} else {
|
||||
return reinterpret_cast<u8 *>(reinterpret_cast<uintptr_t>(p)) + 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
#else
|
||||
#error "Unknown OS for ams::os::impl::InternalReaderWriterBusyMutexValue"
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 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 <vapours.hpp>
|
||||
#if defined(ATMOSPHERE_ARCH_X64)
|
||||
#include <xmmintrin.h>
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
#if defined(ATMOSPHERE_ARCH_X64)
|
||||
|
||||
ALWAYS_INLINE void FenceMemoryStoreStore() { __asm__ __volatile__("" ::: "memory"); _mm_sfence(); }
|
||||
ALWAYS_INLINE void FenceMemoryStoreLoad() { __asm__ __volatile__("" ::: "memory"); _mm_mfence(); }
|
||||
ALWAYS_INLINE void FenceMemoryStoreAny() { __asm__ __volatile__("" ::: "memory"); _mm_mfence(); }
|
||||
|
||||
ALWAYS_INLINE void FenceMemoryLoadStore() { __asm__ __volatile__("" ::: "memory"); _mm_mfence(); }
|
||||
ALWAYS_INLINE void FenceMemoryLoadLoad() { __asm__ __volatile__("" ::: "memory"); _mm_lfence(); }
|
||||
ALWAYS_INLINE void FenceMemoryLoadAny() { __asm__ __volatile__("" ::: "memory"); _mm_mfence(); }
|
||||
|
||||
ALWAYS_INLINE void FenceMemoryAnyStore() { __asm__ __volatile__("" ::: "memory"); _mm_mfence(); }
|
||||
ALWAYS_INLINE void FenceMemoryAnyLoad() { __asm__ __volatile__("" ::: "memory"); _mm_mfence(); }
|
||||
ALWAYS_INLINE void FenceMemoryAnyAny() {__asm__ __volatile__("" ::: "memory"); _mm_mfence(); }
|
||||
|
||||
#elif defined(ATMOSPHERE_ARCH_ARM64)
|
||||
|
||||
ALWAYS_INLINE void FenceMemoryStoreStore() { __asm__ __volatile__("dmb ishst" ::: "memory"); }
|
||||
ALWAYS_INLINE void FenceMemoryStoreLoad() { __asm__ __volatile__("dmb ish" ::: "memory"); }
|
||||
ALWAYS_INLINE void FenceMemoryStoreAny() { __asm__ __volatile__("dmb ish" ::: "memory"); }
|
||||
|
||||
ALWAYS_INLINE void FenceMemoryLoadStore() { __asm__ __volatile__("dmb ishld" ::: "memory"); }
|
||||
ALWAYS_INLINE void FenceMemoryLoadLoad() { __asm__ __volatile__("dmb ishld" ::: "memory"); }
|
||||
ALWAYS_INLINE void FenceMemoryLoadAny() { __asm__ __volatile__("dmb ishld" ::: "memory"); }
|
||||
|
||||
ALWAYS_INLINE void FenceMemoryAnyStore() { __asm__ __volatile__("dmb ish" ::: "memory"); }
|
||||
ALWAYS_INLINE void FenceMemoryAnyLoad() { __asm__ __volatile__("dmb ish" ::: "memory"); }
|
||||
ALWAYS_INLINE void FenceMemoryAnyAny() { __asm__ __volatile__("dmb ish" ::: "memory"); }
|
||||
|
||||
#else
|
||||
|
||||
#error "Unknown architecture for os::impl::FenceMemory* (Generic)"
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -26,7 +26,7 @@ namespace ams::os {
|
||||
private:
|
||||
BusyMutexType m_mutex;
|
||||
public:
|
||||
constexpr explicit BusyMutex() : m_mutex{::ams::os::BusyMutexType::State_Initialized, nullptr, {{}}} { /* ... */ }
|
||||
constexpr explicit BusyMutex() : m_mutex{::ams::os::BusyMutexType::State_Initialized, nullptr, {{AMS_OS_INTERNAL_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZE_ARRAY_VALUES}}} { /* ... */ }
|
||||
|
||||
~BusyMutex() { FinalizeBusyMutex(std::addressof(m_mutex)); }
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 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 <vapours.hpp>
|
||||
|
||||
namespace ams::os {
|
||||
|
||||
#if defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS)
|
||||
#define AMS_OS_IMPL_USE_PTHREADS
|
||||
#elif defined(ATMOSPHERE_OS_WINDOWS)
|
||||
//#define AMS_OS_IMPL_USE_PTHREADS
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -15,6 +15,11 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/os/os_common_config.hpp>
|
||||
|
||||
#if defined(AMS_OS_IMPL_USE_PTHREADS)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
namespace ams::os {
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace ams::os {
|
||||
private:
|
||||
ConditionVariableType m_cv;
|
||||
public:
|
||||
constexpr ConditionVariable() : m_cv{::ams::os::ConditionVariableType::State_Initialized, {{0}}} { /* ... */ }
|
||||
constexpr ConditionVariable() : m_cv{::ams::os::ConditionVariableType::State_Initialized, {AMS_OS_INTERNAL_CONDITION_VARIABLE_IMPL_CONSTANT_INITIALIZER}} { /* ... */ }
|
||||
|
||||
~ConditionVariable() { FinalizeConditionVariable(std::addressof(m_cv)); }
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace ams::os {
|
||||
union {
|
||||
s32 _arr[sizeof(impl::InternalConditionVariableStorage) / sizeof(s32)];
|
||||
impl::InternalConditionVariableStorage _storage;
|
||||
impl::InternalConditionVariableStorageTypeForConstantInitialize _storage_for_constant_initialize;
|
||||
};
|
||||
};
|
||||
static_assert(std::is_trivial<ConditionVariableType>::value);
|
||||
|
||||
@@ -18,6 +18,14 @@
|
||||
|
||||
namespace ams::os {
|
||||
|
||||
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||
using InterruptName = s32;
|
||||
#elif defined(ATMOSPHERE_OS_WINDOWS)
|
||||
using InterruptName = const char *;
|
||||
#elif defined(ATMOSPHERE_OS_LINUX)
|
||||
using InterruptName = const char *;
|
||||
#elif defined(ATMOSPHERE_OS_MACOS)
|
||||
using InterruptName = const char *;
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -30,7 +30,15 @@ namespace ams::os {
|
||||
MemoryPermission_ReadWrite = MemoryPermission_ReadOnly | MemoryPermission_WriteOnly,
|
||||
};
|
||||
|
||||
using MemoryMapping = svc::MemoryMapping;
|
||||
using enum svc::MemoryMapping;
|
||||
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||
using MemoryMapping = svc::MemoryMapping;
|
||||
using enum svc::MemoryMapping;
|
||||
#else
|
||||
enum MemoryMapping : u32 {
|
||||
MemoryMapping_IoRegister = 0,
|
||||
MemoryMapping_Uncached = 1,
|
||||
MemoryMapping_Memory = 2,
|
||||
};
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||
#include <stratosphere/os/impl/os_memory_fence_api.os.horizon.hpp>
|
||||
#elif defined(ATMOSPHERE_OS_WINDOWS) || defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS)
|
||||
#include <stratosphere/os/impl/os_memory_fence_api.os.generic.hpp>
|
||||
#else
|
||||
#error "Unknown os for os::MemoryFence*"
|
||||
#endif
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace ams::os {
|
||||
|
||||
u8 state;
|
||||
bool is_waiting;
|
||||
util::TypedStorage<impl::MultiWaitImpl, sizeof(util::IntrusiveListNode) + sizeof(impl::InternalCriticalSection) + 2 * sizeof(void *) + sizeof(Handle), alignof(void *)> impl_storage;
|
||||
util::TypedStorage<impl::MultiWaitImpl, util::AlignUp(sizeof(util::IntrusiveListNode) + sizeof(impl::InternalCriticalSection) + 2 * sizeof(void *) + sizeof(NativeHandle), alignof(void *)), alignof(void *)> impl_storage;
|
||||
};
|
||||
static_assert(std::is_trivial<MultiWaitType>::value);
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace ams::os {
|
||||
private:
|
||||
MutexType m_mutex;
|
||||
public:
|
||||
constexpr explicit Mutex(bool recursive) : m_mutex{::ams::os::MutexType::State_Initialized, recursive, 0, 0, nullptr, {{0}}} { /* ... */ }
|
||||
constexpr explicit Mutex(bool recursive) : m_mutex{::ams::os::MutexType::State_Initialized, recursive, 0, 0, nullptr, { AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER } } { /* ... */ }
|
||||
|
||||
~Mutex() { FinalizeMutex(std::addressof(m_mutex)); }
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace ams::os {
|
||||
union {
|
||||
s32 _arr[sizeof(impl::InternalCriticalSectionStorage) / sizeof(s32)];
|
||||
impl::InternalCriticalSectionStorage _storage;
|
||||
impl::InternalCriticalSectionStorageTypeForConstantInitialize _storage_for_constant_initialize;
|
||||
};
|
||||
};
|
||||
static_assert(std::is_trivial<MutexType>::value);
|
||||
|
||||
@@ -20,10 +20,24 @@
|
||||
namespace ams::os {
|
||||
|
||||
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||
|
||||
using NativeHandle = svc::Handle;
|
||||
static_assert(std::unsigned_integral<NativeHandle>);
|
||||
|
||||
constexpr inline NativeHandle InvalidNativeHandle = svc::InvalidHandle;
|
||||
|
||||
#elif defined(ATMOSPHERE_OS_WINDOWS)
|
||||
|
||||
using NativeHandle = void *;
|
||||
|
||||
constexpr inline NativeHandle InvalidNativeHandle = nullptr;
|
||||
|
||||
#elif defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS)
|
||||
|
||||
using NativeHandle = s32;
|
||||
|
||||
constexpr inline NativeHandle InvalidNativeHandle = -1;
|
||||
|
||||
#else
|
||||
#error "Unknown OS for os::NativeHandle"
|
||||
#endif
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace ams::os {
|
||||
private:
|
||||
ReaderWriterBusyMutexType m_rw_mutex;
|
||||
public:
|
||||
constexpr explicit ReaderWriterBusyMutex() : m_rw_mutex{{0}} { /* ... */ }
|
||||
constexpr explicit ReaderWriterBusyMutex() : m_rw_mutex{ { AMS_OS_INTERNAL_READER_WRITER_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZER } } { /* ... */ }
|
||||
|
||||
void AcquireReadLock() {
|
||||
return os::AcquireReadLockBusyMutex(std::addressof(m_rw_mutex));
|
||||
|
||||
@@ -27,9 +27,15 @@ namespace ams::os {
|
||||
private:
|
||||
ReaderWriterLockType m_rw_lock;
|
||||
public:
|
||||
constexpr explicit ReaderWriterLock() : m_rw_lock{{}, 0, ::ams::os::ReaderWriterLockType::State_Initialized, nullptr, 0, {}, {}} { /* ... */ }
|
||||
constexpr explicit ReaderWriterLock() : m_rw_lock {{ { MakeConstantInitializedLockCount(), 0 } }, 0, ::ams::os::ReaderWriterLockType::State_Initialized, nullptr, 0, {AMS_OS_INTERNAL_CONDITION_VARIABLE_IMPL_CONSTANT_INITIALIZER}, {AMS_OS_INTERNAL_CONDITION_VARIABLE_IMPL_CONSTANT_INITIALIZER} } {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
~ReaderWriterLock() { os::FinalizeReaderWriterLock(std::addressof(m_rw_lock)); }
|
||||
constexpr ~ReaderWriterLock() {
|
||||
if (!std::is_constant_evaluated()) {
|
||||
os::FinalizeReaderWriterLock(std::addressof(m_rw_lock));
|
||||
}
|
||||
}
|
||||
|
||||
void AcquireReadLock() {
|
||||
return os::AcquireReadLock(std::addressof(m_rw_lock));
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace ams::os {
|
||||
|
||||
struct ReaderWriterLockType;
|
||||
|
||||
void InitalizeReaderWriterLock(ReaderWriterLockType *rw_lock);
|
||||
void InitializeReaderWriterLock(ReaderWriterLockType *rw_lock);
|
||||
void FinalizeReaderWriterLock(ReaderWriterLockType *rw_lock);
|
||||
|
||||
void AcquireReadLock(ReaderWriterLockType *rw_lock);
|
||||
|
||||
@@ -33,6 +33,7 @@ namespace ams::os {
|
||||
union {
|
||||
s32 _arr[sizeof(impl::InternalCriticalSectionStorage) / sizeof(s32)];
|
||||
impl::InternalCriticalSectionStorage cs_storage;
|
||||
impl::InternalCriticalSectionStorageTypeForConstantInitialize _storage_for_constant_initialize;
|
||||
};
|
||||
util::BitPack32 counter;
|
||||
};
|
||||
@@ -59,12 +60,29 @@ namespace ams::os {
|
||||
union {
|
||||
s32 _arr[sizeof(impl::InternalConditionVariableStorage) / sizeof(s32)];
|
||||
impl::InternalConditionVariableStorage _storage;
|
||||
impl::InternalConditionVariableStorageTypeForConstantInitialize _storage_for_constant_initialize;
|
||||
} cv_read_lock;
|
||||
union {
|
||||
s32 _arr[sizeof(impl::InternalConditionVariableStorage) / sizeof(s32)];
|
||||
impl::InternalConditionVariableStorage _storage;
|
||||
impl::InternalConditionVariableStorageTypeForConstantInitialize _storage_for_constant_initialize;
|
||||
} cv_write_lock;
|
||||
};
|
||||
static_assert(std::is_trivial<ReaderWriterLockType>::value);
|
||||
|
||||
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||
consteval ReaderWriterLockType::LockCount MakeConstantInitializedLockCount() { return {}; }
|
||||
#elif defined(ATMOSPHERE_OS_WINDOWS) || defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS)
|
||||
/* If windows/linux, require that the lock counter have guaranteed alignment, so that we may constant-initialize. */
|
||||
static_assert(alignof(ReaderWriterLockType) == sizeof(u64));
|
||||
consteval ReaderWriterLockType::LockCount MakeConstantInitializedLockCount() {
|
||||
return ReaderWriterLockType::LockCount {
|
||||
{ AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER },
|
||||
{},
|
||||
};
|
||||
}
|
||||
#else
|
||||
#error "Unknown OS for constant initialized RW-lock LockCount"
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace ams::os {
|
||||
union {
|
||||
s32 _arr[sizeof(impl::InternalConditionVariableStorage) / sizeof(s32)];
|
||||
impl::InternalConditionVariableStorage _storage;
|
||||
impl::InternalConditionVariableStorageTypeForConstantInitialize _storage_for_constant_initialize;
|
||||
};
|
||||
|
||||
ALWAYS_INLINE void Initialize() {
|
||||
@@ -52,7 +53,7 @@ namespace ams::os {
|
||||
private:
|
||||
SdkConditionVariableType m_cv;
|
||||
public:
|
||||
constexpr SdkConditionVariable() : m_cv{{0}} { /* ... */ }
|
||||
constexpr SdkConditionVariable() : m_cv{{AMS_OS_INTERNAL_CONDITION_VARIABLE_IMPL_CONSTANT_INITIALIZER}} { /* ... */ }
|
||||
|
||||
ALWAYS_INLINE void Wait(SdkMutex &m) {
|
||||
return m_cv.Wait(m.m_mutex);
|
||||
|
||||
@@ -22,10 +22,16 @@ namespace ams::os {
|
||||
|
||||
class SdkConditionVariable;
|
||||
|
||||
struct ThreadType;
|
||||
|
||||
struct SdkMutexType {
|
||||
#if !defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD)
|
||||
os::ThreadType *owner_thread;
|
||||
#endif
|
||||
union {
|
||||
s32 _arr[sizeof(impl::InternalCriticalSectionStorage) / sizeof(s32)];
|
||||
impl::InternalCriticalSectionStorage _storage;
|
||||
impl::InternalCriticalSectionStorageTypeForConstantInitialize _storage_for_constant_initialize;
|
||||
};
|
||||
};
|
||||
static_assert(std::is_trivial<SdkMutexType>::value);
|
||||
@@ -44,7 +50,11 @@ namespace ams::os {
|
||||
private:
|
||||
SdkMutexType m_mutex;
|
||||
public:
|
||||
constexpr SdkMutex() : m_mutex{{0}} { /* ... */ }
|
||||
#if defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD)
|
||||
constexpr SdkMutex() : m_mutex{{AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER}} { /* ... */ }
|
||||
#else
|
||||
constexpr SdkMutex() : m_mutex{nullptr, {AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER}} { /* ... */ }
|
||||
#endif
|
||||
|
||||
ALWAYS_INLINE void Lock() { return os::LockSdkMutex(std::addressof(m_mutex)); }
|
||||
ALWAYS_INLINE bool TryLock() { return os::TryLockSdkMutex(std::addressof(m_mutex)); }
|
||||
|
||||
@@ -23,9 +23,13 @@ namespace ams::os {
|
||||
class SdkConditionVariable;
|
||||
|
||||
struct SdkRecursiveMutexType {
|
||||
#if !defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD)
|
||||
os::ThreadType *owner_thread;
|
||||
#endif
|
||||
union {
|
||||
s32 _arr[sizeof(impl::InternalCriticalSectionStorage) / sizeof(s32)];
|
||||
impl::InternalCriticalSectionStorage _storage;
|
||||
impl::InternalCriticalSectionStorageTypeForConstantInitialize _storage_for_constant_initialize;
|
||||
};
|
||||
u32 recursive_count;
|
||||
};
|
||||
@@ -45,7 +49,11 @@ namespace ams::os {
|
||||
private:
|
||||
SdkRecursiveMutexType m_mutex;
|
||||
public:
|
||||
constexpr SdkRecursiveMutex() : m_mutex{{0}, 0} { /* ... */ }
|
||||
#if defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD)
|
||||
constexpr SdkRecursiveMutex() : m_mutex{ { AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER }, 0 } { /* ... */ }
|
||||
#else
|
||||
constexpr SdkRecursiveMutex() : m_mutex{ nullptr, { AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER }, 0 } { /* ... */ }
|
||||
#endif
|
||||
|
||||
ALWAYS_INLINE void Lock() { return os::LockSdkRecursiveMutex(std::addressof(m_mutex)); }
|
||||
ALWAYS_INLINE bool TryLock() { return os::TryLockSdkRecursiveMutex(std::addressof(m_mutex)); }
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 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 <stratosphere/os/os_common_types.hpp>
|
||||
#include <stratosphere/os/os_thread_types.hpp>
|
||||
#include <stratosphere/os/os_sdk_thread_types.hpp>
|
||||
#include <stratosphere/os/os_thread_local_storage_common.hpp>
|
||||
|
||||
namespace ams::os {
|
||||
|
||||
ALWAYS_INLINE SdkInternalTlsType *GetSdkInternalTlsArray(ThreadType *thread = os::GetCurrentThread()) {
|
||||
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||
return std::addressof(thread->sdk_internal_tls);
|
||||
#else
|
||||
return reinterpret_cast<SdkInternalTlsType *>(std::addressof(thread->tls_value_array[TlsSlotCountMax]));
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 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 <stratosphere/os/os_common_types.hpp>
|
||||
#include <stratosphere/os/os_thread_local_storage_common.hpp>
|
||||
|
||||
namespace ams::os {
|
||||
|
||||
struct SdkInternalTlsType {
|
||||
uintptr_t sf_inline_context;
|
||||
};
|
||||
static_assert(util::is_pod<SdkInternalTlsType>::value);
|
||||
static_assert((sizeof(SdkInternalTlsType) % sizeof(uintptr_t)) == 0);
|
||||
|
||||
constexpr inline size_t SdkInternalTlsCount = sizeof(SdkInternalTlsType) / sizeof(uintptr_t);
|
||||
static_assert(SdkInternalTlsCount <= SdkTlsSlotCountMax);
|
||||
|
||||
}
|
||||
@@ -40,8 +40,6 @@ namespace ams::os {
|
||||
s32 ResumeThread(ThreadType *thread);
|
||||
s32 GetThreadSuspendCount(const ThreadType *thread);
|
||||
|
||||
void CancelThreadSynchronization(ThreadType *Thread);
|
||||
|
||||
/* TODO: void GetThreadContext(ThreadContextInfo *out_context, const ThreadType *thread); */
|
||||
|
||||
s32 ChangeThreadPriority(ThreadType *thread, s32 priority);
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace ams::os {
|
||||
|
||||
using TlsDestructor = void (*)(uintptr_t arg);
|
||||
|
||||
constexpr inline size_t TlsSlotCountMax = 16;
|
||||
constexpr inline size_t TlsSlotCountMax = 16;
|
||||
constexpr inline size_t SdkTlsSlotCountMax = 16;
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <stratosphere/os/os_thread_local_storage_api.hpp>
|
||||
#include <stratosphere/os/impl/os_internal_critical_section.hpp>
|
||||
#include <stratosphere/os/impl/os_internal_condition_variable.hpp>
|
||||
#include <stratosphere/os/os_sdk_thread_types.hpp>
|
||||
|
||||
namespace ams::os {
|
||||
|
||||
@@ -30,10 +31,21 @@ namespace ams::os {
|
||||
|
||||
}
|
||||
|
||||
#if !defined(AMS_OS_IMPL_USE_PTHREADS)
|
||||
using ThreadId = u64;
|
||||
#else
|
||||
/* TODO: decide whether using pthread_id_np_t or not more thoroughly. */
|
||||
#if defined(ATMOSPHERE_OS_MACOS)
|
||||
#define AMS_OS_IMPL_USE_PTHREADID_NP_FOR_THREAD_ID
|
||||
#endif
|
||||
|
||||
/* TODO */
|
||||
using ThreadImpl = ::Thread;
|
||||
#if defined(AMS_OS_IMPL_USE_PTHREADID_NP_FOR_THREAD_ID)
|
||||
using ThreadId = u64;
|
||||
#else
|
||||
static_assert(sizeof(pthread_t) <= sizeof(u64));
|
||||
using ThreadId = pthread_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct ThreadType {
|
||||
static constexpr u16 Magic = 0xF5A5;
|
||||
@@ -50,6 +62,8 @@ namespace ams::os {
|
||||
util::TypedStorage<impl::MultiWaitObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> waitlist;
|
||||
uintptr_t reserved[4];
|
||||
u8 state;
|
||||
bool stack_is_aliased;
|
||||
bool auto_registered;
|
||||
u8 suspend_count;
|
||||
u16 magic;
|
||||
s16 base_priority;
|
||||
@@ -57,21 +71,49 @@ namespace ams::os {
|
||||
char name_buffer[ThreadNameLengthMax];
|
||||
const char *name_pointer;
|
||||
ThreadId thread_id;
|
||||
void *original_stack;
|
||||
void *stack;
|
||||
size_t stack_size;
|
||||
ThreadFunction function;
|
||||
void *initial_fiber;
|
||||
void *current_fiber;
|
||||
void *argument;
|
||||
|
||||
/* NOTE: Here, Nintendo stores the TLS array. This is handled by libnx in our case. */
|
||||
/* However, we need to access certain values in other threads' TLS (Nintendo uses a hardcoded layout for SDK tls members...) */
|
||||
/* These members are tls slot holders in sdk code, but just normal thread type members under our scheme. */
|
||||
uintptr_t atomic_sf_inline_context;
|
||||
|
||||
mutable impl::InternalCriticalSectionStorage cs_thread;
|
||||
mutable impl::InternalConditionVariableStorage cv_thread;
|
||||
|
||||
/* The following members are arch/os specific. */
|
||||
#if defined(AMS_OS_IMPL_USE_PTHREADS)
|
||||
|
||||
mutable uintptr_t tls_value_array[TlsSlotCountMax + SdkTlsSlotCountMax];
|
||||
|
||||
mutable impl::InternalCriticalSectionStorage cs_pthread_exit;
|
||||
mutable impl::InternalConditionVariableStorage cv_pthread_exit;
|
||||
bool exited_pthread;
|
||||
|
||||
pthread_t pthread;
|
||||
u64 affinity_mask;
|
||||
int ideal_core;
|
||||
|
||||
#elif defined(ATMOSPHERE_OS_HORIZON)
|
||||
/* NOTE: Here, Nintendo stores the TLS array. This is handled by libnx in our case. */
|
||||
/* However, we need to access certain values in other threads' TLS (Nintendo uses a hardcoded layout for SDK tls members...) */
|
||||
/* These members are tls slot holders in sdk code, but just normal thread type members under our scheme. */
|
||||
SdkInternalTlsType sdk_internal_tls;
|
||||
|
||||
using ThreadImpl = ::Thread;
|
||||
|
||||
ThreadImpl *thread_impl;
|
||||
ThreadImpl thread_impl_storage;
|
||||
#elif defined(ATMOSPHERE_OS_WINDOWS)
|
||||
|
||||
mutable uintptr_t tls_value_array[TlsSlotCountMax + SdkTlsSlotCountMax];
|
||||
|
||||
NativeHandle native_handle;
|
||||
int ideal_core;
|
||||
u64 affinity_mask;
|
||||
|
||||
#endif
|
||||
};
|
||||
static_assert(std::is_trivial<ThreadType>::value);
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 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 <vapours.hpp>
|
||||
#include <stratosphere/os/os_virtual_address_memory_common.hpp>
|
||||
#include <stratosphere/os/os_virtual_address_memory_types.hpp>
|
||||
#include <stratosphere/os/os_virtual_address_memory_api.hpp>
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 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 <vapours.hpp>
|
||||
#include <stratosphere/os/os_virtual_address_memory_common.hpp>
|
||||
#include <stratosphere/os/os_virtual_address_memory_types.hpp>
|
||||
|
||||
namespace ams::os {
|
||||
|
||||
void InitializeVirtualAddressMemory();
|
||||
|
||||
Result AllocateAddressRegion(uintptr_t *out, size_t size);
|
||||
Result AllocateMemory(uintptr_t *out, size_t size);
|
||||
Result AllocateMemoryPages(uintptr_t address, size_t size);
|
||||
|
||||
Result FreeAddressRegion(uintptr_t address);
|
||||
Result FreeMemoryPages(uintptr_t address, size_t size);
|
||||
|
||||
VirtualAddressMemoryResourceUsage GetVirtualAddressMemoryResourceUsage();
|
||||
|
||||
bool IsVirtualAddressMemoryEnabled();
|
||||
|
||||
}
|
||||
@@ -15,11 +15,9 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/os/os_common_types.hpp>
|
||||
#include <stratosphere/os/os_memory_common.hpp>
|
||||
|
||||
namespace ams::os {
|
||||
|
||||
bool IsVirtualAddressMemoryEnabled();
|
||||
constexpr inline size_t AddressRegionAlignment = 64_KB;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 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 <vapours.hpp>
|
||||
#include <stratosphere/os/os_virtual_address_memory_common.hpp>
|
||||
|
||||
namespace ams::os {
|
||||
|
||||
struct VirtualAddressMemoryResourceUsage {
|
||||
size_t assigned_size;
|
||||
size_t used_size;
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user