ams: support building unit test programs on windows/linux/macos

This commit is contained in:
Michael Scire
2022-03-06 12:08:20 -08:00
committed by SciresM
parent 9a38be201a
commit 64a97576d0
756 changed files with 33359 additions and 9372 deletions

View File

@@ -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(); }

View File

@@ -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
}

View File

@@ -35,4 +35,6 @@ namespace ams::os::impl {
void Unlock();
};
#define AMS_OS_INTERNAL_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZE_ARRAY_VALUES 0
}

View File

@@ -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();
}

View File

@@ -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}
}

View File

@@ -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 }
}

View File

@@ -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
}

View File

@@ -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(); }

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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);
};
}

View File

@@ -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

View File

@@ -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}
}

View File

@@ -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}
}

View File

@@ -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}
}

View File

@@ -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}
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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)); }

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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)); }

View File

@@ -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);

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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)); }

View File

@@ -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);

View File

@@ -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

View File

@@ -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));

View File

@@ -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));

View File

@@ -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);

View File

@@ -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
}

View File

@@ -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);

View File

@@ -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)); }

View File

@@ -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)); }

View File

@@ -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
}
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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>

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -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;
};
}