Switch to subrepos

git subrepo clone https://github.com/open-ead/sead lib/sead

subrepo:
  subdir:   "lib/sead"
  merged:   "1b66e825d"
upstream:
  origin:   "https://github.com/open-ead/sead"
  branch:   "master"
  commit:   "1b66e825d"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"

git subrepo clone (merge) https://github.com/open-ead/nnheaders lib/NintendoSDK

subrepo:
  subdir:   "lib/NintendoSDK"
  merged:   "9ee21399f"
upstream:
  origin:   "https://github.com/open-ead/nnheaders"
  branch:   "master"
  commit:   "9ee21399f"
git-subrepo:
  version:  "0.4.3"
  origin:   "ssh://git@github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"

git subrepo clone https://github.com/open-ead/agl lib/agl

subrepo:
  subdir:   "lib/agl"
  merged:   "7c063271b"
upstream:
  origin:   "https://github.com/open-ead/agl"
  branch:   "master"
  commit:   "7c063271b"
git-subrepo:
  version:  "0.4.3"
  origin:   "ssh://git@github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"

git subrepo clone https://github.com/open-ead/EventFlow lib/EventFlow

subrepo:
  subdir:   "lib/EventFlow"
  merged:   "c35d21b34"
upstream:
  origin:   "https://github.com/open-ead/EventFlow"
  branch:   "master"
  commit:   "c35d21b34"
git-subrepo:
  version:  "0.4.3"
  origin:   "ssh://git@github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"
This commit is contained in:
Léo Lam
2022-03-21 19:25:20 +01:00
parent ffcc7f659e
commit 18c60323a9
457 changed files with 52182 additions and 16 deletions
@@ -0,0 +1,30 @@
#ifndef SEAD_THREAD_THREAD_LOCAL_STORAGE_H_
#include "thread/seadThreadLocalStorage.h"
#endif
#include "basis/seadRawPrint.h"
namespace sead
{
inline ThreadLocalStorage::ThreadLocalStorage()
{
[[maybe_unused]] auto result = nn::os::AllocateTlsSlot(&mTlsSlot, nullptr);
SEAD_ASSERT(result.IsSuccess());
}
inline ThreadLocalStorage::~ThreadLocalStorage()
{
nn::os::FreeTlsSlot(mTlsSlot);
}
inline void ThreadLocalStorage::setValue(uintptr_t value)
{
static_assert(sizeof(uintptr_t) == sizeof(u64), "uintptr_t and u64 should have the same size");
nn::os::SetTlsValue(mTlsSlot, value);
}
inline uintptr_t ThreadLocalStorage::getValue() const
{
return nn::os::GetTlsValue(mTlsSlot);
}
} // namespace sead
+287
View File
@@ -0,0 +1,287 @@
#pragma once
#ifdef NNSDK
#include <atomic>
#endif
namespace sead
{
struct AtomicDirectInitTag
{
};
template <class T>
struct AtomicBase
{
public:
AtomicBase(T value = {}); // NOLINT(google-explicit-constructor)
/// Directly initialises the underlying atomic with the specified value.
/// Note that initialisation is not atomic.
AtomicBase(AtomicDirectInitTag, T value);
AtomicBase(const AtomicBase& rhs) { *this = rhs; }
operator T() const { return load(); }
AtomicBase& operator=(const AtomicBase& rhs)
{
store(rhs.load());
return *this;
}
AtomicBase& operator=(T value)
{
store(value);
return *this;
}
/// Load the current value, as if with memory_order_relaxed.
T load() const;
/// Store a new value, as if with memory_order_relaxed.
void store(T value);
/// Non-atomically store a new value.
void storeNonAtomic(T value);
/// Exchange/swap the current value, as if with memory_order_relaxed.
/// @return the previous value
T exchange(T value);
/// Load the current value and if it is equal to `expected`, store `desired`
/// as if with memory_order_relaxed.
/// Otherwise, this sets `original` to the current value.
/// @param expected The value expected to be found in the atomic object, and to be replaced.
/// @param desired The new value to store in the atomic object if `expected` was found.
/// @param original The value that was found in the atomic object if the comparison fails. May
/// be null. Note that this is only updated when false is returned.
/// @return true if and only if the value was modified
bool compareExchange(T expected, T desired, T* original = nullptr);
protected:
#ifdef NNSDK
// Nintendo appears to have manually implemented atomics with volatile and platform specific
// intrinsics (e.g. __builtin_arm_ldrex).
// For ease of implementation and portability, we will use std::atomic and cast to volatile
// when necessary. That is formally undefined behavior, but it should be safe because
// sead is built with -fno-strict-aliasing and because of the following static assertions.
std::atomic<T> mValue;
static_assert(sizeof(mValue) == sizeof(T),
"std::atomic<T> and T do not have the same size; unsupported case");
static_assert(alignof(decltype(mValue)) == alignof(volatile T),
"std::atomic<T> and T do not have the same alignment; unsupported case");
static_assert(std::atomic<T>::is_always_lock_free,
"std::atomic<T>::is_always_lock_free is not true; unsupported case");
const volatile T* getValuePtr() const { return reinterpret_cast<const volatile T*>(&mValue); }
volatile T* getValuePtr() { return reinterpret_cast<volatile T*>(&mValue); }
#endif
};
template <class T>
struct Atomic : AtomicBase<T>
{
using AtomicBase<T>::AtomicBase;
using AtomicBase<T>::operator=;
T fetchAdd(T x);
T fetchSub(T x);
T fetchAnd(T x);
T fetchOr(T x);
T fetchXor(T x);
T increment() { return fetchAdd(1); }
T decrement() { return fetchSub(1); }
bool isBitOn(unsigned int bit) const;
/// @return whether the bit was cleared and is now set.
bool setBitOn(unsigned int bit);
/// @return whether the bit was set and is now cleared.
bool setBitOff(unsigned int bit);
T operator+=(T x) { return fetchAdd(x); }
T operator-=(T x) { return fetchSub(x); }
T operator&=(T x) { return fetchAnd(x); }
T operator|=(T x) { return fetchOr(x); }
T operator^=(T x) { return fetchXor(x); }
T operator++() { return fetchAdd(1) + 1; }
T operator++(int) { return fetchAdd(1); }
T operator--() { return fetchSub(1) - 1; }
T operator--(int) { return fetchSub(1); }
};
/// Specialization for pointer types.
template <class T>
struct Atomic<T*> : AtomicBase<T*>
{
using AtomicBase<T*>::AtomicBase;
using AtomicBase<T*>::operator=;
T& operator*() const { return *this->load(); }
T* operator->() const { return this->load(); }
};
// Implementation.
#ifdef NNSDK
template <class T>
inline AtomicBase<T>::AtomicBase(T value)
{
storeNonAtomic(value);
}
template <class T>
inline AtomicBase<T>::AtomicBase(AtomicDirectInitTag, T value) : mValue(value)
{
}
template <class T>
inline T AtomicBase<T>::load() const
{
#ifdef MATCHING_HACK_NX_CLANG
// Using std::atomic<T>::load prevents LLVM from folding ldr+sext into ldrsw.
return *getValuePtr();
#else
return mValue.load(std::memory_order_relaxed);
#endif
}
template <class T>
inline void AtomicBase<T>::store(T value)
{
mValue.store(value, std::memory_order_relaxed);
}
template <class T>
inline void AtomicBase<T>::storeNonAtomic(T value)
{
*getValuePtr() = value;
}
template <class T>
inline T AtomicBase<T>::exchange(T value)
{
return mValue.exchange(value, std::memory_order_relaxed);
}
template <class T>
inline bool AtomicBase<T>::compareExchange(T expected, T desired, T* original)
{
#ifdef MATCHING_HACK_NX_CLANG
// Unlike Clang (https://reviews.llvm.org/D13033), Nintendo's implementation does not use clrex.
do
{
T value = __builtin_arm_ldrex(getValuePtr());
if (value != expected)
{
if (original)
*original = value;
return false;
}
} while (__builtin_arm_strex(desired, getValuePtr()));
return true;
#else
T value = expected;
if (mValue.compare_exchange_strong(value, desired, std::memory_order_relaxed))
return true;
if (original)
*original = value;
return false;
#endif
}
#ifdef MATCHING_HACK_NX_CLANG
namespace detail
{
// To match Nintendo's implementation of atomics.
template <typename T, typename F>
inline T atomicReadModifyWrite(volatile T* value_ptr, F op)
{
T value;
do
{
value = __builtin_arm_ldrex(value_ptr);
} while (__builtin_arm_strex(op(value), value_ptr));
return value;
}
} // namespace detail
#endif
template <class T>
inline T Atomic<T>::fetchAdd(T x)
{
#ifdef MATCHING_HACK_NX_CLANG
return detail::atomicReadModifyWrite(this->getValuePtr(), [&](T val) { return val + x; });
#else
return this->mValue.fetch_add(x, std::memory_order_relaxed);
#endif
}
template <class T>
inline T Atomic<T>::fetchSub(T x)
{
#ifdef MATCHING_HACK_NX_CLANG
return detail::atomicReadModifyWrite(this->getValuePtr(), [&](T val) { return val - x; });
#else
return this->mValue.fetch_sub(x, std::memory_order_relaxed);
#endif
}
template <class T>
inline T Atomic<T>::fetchAnd(T x)
{
#ifdef MATCHING_HACK_NX_CLANG
return detail::atomicReadModifyWrite(this->getValuePtr(), [&](T val) { return val & x; });
#else
return this->mValue.fetch_and(x, std::memory_order_relaxed);
#endif
}
template <class T>
inline T Atomic<T>::fetchOr(T x)
{
#ifdef MATCHING_HACK_NX_CLANG
return detail::atomicReadModifyWrite(this->getValuePtr(), [&](T val) { return val | x; });
#else
return this->mValue.fetch_or(x, std::memory_order_relaxed);
#endif
}
template <class T>
inline T Atomic<T>::fetchXor(T x)
{
#ifdef MATCHING_HACK_NX_CLANG
return detail::atomicReadModifyWrite(this->getValuePtr(), [&](T val) { return val ^ x; });
#else
return this->mValue.fetch_xor(x, std::memory_order_relaxed);
#endif
}
template <class T>
bool Atomic<T>::isBitOn(unsigned int bit) const
{
return (this->load() & (1 << bit)) != 0;
}
template <class T>
bool Atomic<T>::setBitOn(unsigned int bit)
{
#ifdef MATCHING_HACK_NX_CLANG
const auto old = detail::atomicReadModifyWrite(this->getValuePtr(),
[bit](T val) { return val | (1 << bit); });
#else
const auto old = this->mValue.fetch_or(1 << bit, std::memory_order_relaxed);
#endif
return (old & (1 << bit)) == 0;
}
template <class T>
bool Atomic<T>::setBitOff(unsigned int bit)
{
#ifdef MATCHING_HACK_NX_CLANG
const auto old = detail::atomicReadModifyWrite(this->getValuePtr(),
[bit](T val) { return val & ~(1 << bit); });
#else
const auto old = this->mValue.fetch_and(~(1 << bit), std::memory_order_relaxed);
#endif
return (old & (1 << bit)) != 0;
}
#else // NNSDK
#error "Unknown platform"
#endif
} // namespace sead
@@ -0,0 +1,46 @@
#ifndef SEAD_CRITICAL_SECTION_H_
#define SEAD_CRITICAL_SECTION_H_
#if defined(cafe)
#include <cafe.h>
#elif defined(NNSDK)
#include <nn/os.h>
#endif
#include <basis/seadTypes.h>
#include <heap/seadDisposer.h>
namespace sead
{
class Heap;
class CriticalSection : public IDisposer
{
public:
CriticalSection();
explicit CriticalSection(Heap* disposer_heap);
CriticalSection(Heap* disposer_heap, HeapNullOption heap_null_option);
~CriticalSection() override;
CriticalSection(const CriticalSection&) = delete;
CriticalSection& operator=(const CriticalSection&) = delete;
void lock();
bool tryLock();
void unlock();
// For compatibility with the standard Lockable concept.
bool try_lock() { return tryLock(); }
#if defined(cafe)
OSMutex mCriticalSectionInner;
#elif defined(NNSDK)
nn::os::MutexType mCriticalSectionInner;
#else
#error "Unknown platform"
#endif
};
} // namespace sead
#endif // SEAD_CRITICAL_SECTION_H_
@@ -0,0 +1,25 @@
#pragma once
#include <thread/seadMessageQueue.h>
#include <thread/seadThread.h>
namespace sead
{
template <typename A1, typename A2>
class IDelegate2;
class DelegateThread : public Thread
{
public:
DelegateThread(const SafeString& name, IDelegate2<Thread*, MessageQueue::Element>* delegate,
Heap* heap, s32 priority, MessageQueue::BlockType block_type,
MessageQueue::Element quit_msg, s32 stack_size, s32 message_queue_size);
~DelegateThread() override;
protected:
void calc_(MessageQueue::Element msg) override;
IDelegate2<Thread*, MessageQueue::Element>* mDelegate;
};
} // namespace sead
+52
View File
@@ -0,0 +1,52 @@
#pragma once
#ifdef NNSDK
#include <nn/os.h>
#endif
#include "heap/seadDisposer.h"
#include "time/seadTickSpan.h"
namespace sead
{
class Heap;
class Event : public IDisposer
{
public:
Event();
explicit Event(bool manual_reset);
explicit Event(Heap* disposer_heap);
Event(Heap* disposer_heap, bool manual_reset);
Event(Heap* disposer_heap, IDisposer::HeapNullOption heap_null_option);
Event(Heap* disposer_heap, IDisposer::HeapNullOption heap_null_option, bool manual_reset);
~Event() override;
Event(const Event&) = delete;
Event& operator=(const Event&) = delete;
void initialize(bool manual_reset);
void wait();
bool wait(TickSpan duration);
void setSignal();
void resetSignal();
private:
void setInitialized([[maybe_unused]] bool initialized)
{
#ifdef SEAD_DEBUG
mInitialized = initialized;
#endif
}
#ifdef NNSDK
nn::os::LightEventType mEventInner;
#else
#error "Unknown platform"
#endif
#ifdef SEAD_DEBUG
bool mInitialized = false;
#endif
};
} // namespace sead
@@ -0,0 +1,47 @@
#pragma once
#ifdef NNSDK
#include <nn/os.h>
#endif
namespace sead
{
class Heap;
class MessageQueue
{
public:
#ifdef NNSDK
using Element = s64;
#else
#error "Unknown platform"
using Element = u64;
#endif
enum class BlockType
{
Blocking = 0,
NonBlocking = 1,
};
MessageQueue();
~MessageQueue();
void allocate(s32 size, Heap* heap);
void free();
bool push(Element message, BlockType block_type);
Element pop(BlockType block_type);
Element peek(BlockType block_type) const;
bool jam(Element message, BlockType block_type);
static constexpr Element cNullElement = 0;
private:
#ifdef NNSDK
nn::os::MessageQueueType mMessageQueueInner;
Element* mBuffer = nullptr;
#else
#error "Unknown platform"
#endif
};
} // namespace sead
+43
View File
@@ -0,0 +1,43 @@
#pragma once
#if defined(cafe)
#include <cafe.h>
#elif defined(NNSDK)
#include <nn/os.h>
#endif
#include <basis/seadTypes.h>
#include <heap/seadDisposer.h>
namespace sead
{
class Heap;
class Mutex : public IDisposer
{
public:
Mutex();
explicit Mutex(Heap* disposer_heap);
Mutex(Heap* disposer_heap, HeapNullOption heap_null_option);
~Mutex() override;
Mutex(const Mutex&) = delete;
Mutex& operator=(const Mutex&) = delete;
void lock();
bool tryLock();
void unlock();
// For compatibility with the standard Lockable concept.
bool try_lock() { return tryLock(); }
#if defined(cafe)
OSMutex mMutexInner;
#elif defined(NNSDK)
nn::os::MutexType mMutexInner;
#else
#error "Unknown platform"
#endif
};
} // namespace sead
@@ -0,0 +1,40 @@
#pragma once
#include "thread/seadAtomic.h"
#include "thread/seadSemaphore.h"
namespace sead
{
class Thread;
class ReadWriteLock
{
public:
ReadWriteLock();
~ReadWriteLock();
void readLock();
void readUnlock();
void writeLock();
void writeUnlock();
private:
class SemaphoreLock
{
public:
SemaphoreLock();
void lock();
void unlock();
private:
Semaphore mSemaphore{0, 0x7FFF};
Atomic<u32> mLockCount{0};
};
Atomic<u32> mNumReaders{0};
Atomic<u32> mNumWriters{0};
SemaphoreLock mReadLock;
SemaphoreLock mWriteLock;
Thread* mWriterThread = nullptr;
u32 mWritingThreadCount{0};
};
} // namespace sead
+59
View File
@@ -0,0 +1,59 @@
#pragma once
#ifdef NNSDK
#include <nn/os.h>
#endif
#include "heap/seadDisposer.h"
namespace sead
{
class Heap;
class Semaphore : public IDisposer
{
public:
Semaphore();
explicit Semaphore(s32 initial_count);
Semaphore(s32 initial_count, s32 max_count);
explicit Semaphore(Heap* heap);
Semaphore(Heap* heap, s32 initial_count);
Semaphore(Heap* heap, s32 initial_count, s32 max_count);
Semaphore(Heap* heap, HeapNullOption heap_null_option);
Semaphore(Heap* heap, HeapNullOption heap_null_option, s32 initial_count);
Semaphore(Heap* heap, HeapNullOption heap_null_option, s32 initial_count, s32 max_count);
~Semaphore() override;
Semaphore(const Semaphore&) = delete;
Semaphore& operator=(const Semaphore&) = delete;
void initialize(s32 initial_count) { initialize(initial_count, initial_count); }
void initialize(s32 initial_count, s32 max_count);
void lock();
bool tryLock();
void unlock();
bool try_lock() { return tryLock(); }
private:
void setInitialized([[maybe_unused]] bool initialized)
{
#ifdef SEAD_DEBUG
mInitialized = initialized;
#endif
}
#ifdef NNSDK
nn::os::SemaphoreType mSemaphoreInner;
#else
#error "Unknown platform"
#endif
#ifdef SEAD_DEBUG
bool mInitialized = false;
#endif
};
} // namespace sead
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#include "basis/seadTypes.h"
#include "thread/seadAtomic.h"
namespace sead
{
class Thread;
class SpinLock
{
public:
SpinLock();
~SpinLock();
SpinLock(const SpinLock&) = delete;
SpinLock& operator=(const SpinLock&) = delete;
void lock();
bool tryLock();
void unlock();
bool try_lock() { return tryLock(); }
private:
Atomic<Thread*> mOwnerThread;
u32 mCount = 0;
};
} // namespace sead
+199
View File
@@ -0,0 +1,199 @@
#pragma once
#ifdef NNSDK
#include <nn/os.h>
#endif
#include <basis/seadRawPrint.h>
#include <container/seadTList.h>
#include <heap/seadDisposer.h>
#include <heap/seadHeapMgr.h>
#include <hostio/seadHostIONode.h>
#include <hostio/seadHostIOReflexible.h>
#include <mc/seadCoreInfo.h>
#include <prim/seadEnum.h>
#include <prim/seadNamable.h>
#include <prim/seadSafeString.h>
#include <prim/seadScopedLock.h>
#include <thread/seadMessageQueue.h>
#include <thread/seadThreadLocalStorage.h>
#include <time/seadTickSpan.h>
namespace sead
{
class Heap;
class Thread;
using ThreadList = TList<Thread*>;
using ThreadListNode = TListNode<Thread*>;
class Thread : public IDisposer, public INamable, public hostio::Reflexible
{
public:
SEAD_ENUM(State, cInitialized, cRunning, cQuitting, cTerminated, cReleased);
Thread(const SafeString& name, Heap* heap, s32 priority, MessageQueue::BlockType block_type,
MessageQueue::Element quit_msg, s32 stack_size, s32 message_queue_size);
~Thread() override;
Thread(const Thread&) = delete;
Thread& operator=(const Thread&) = delete;
virtual void destroy() { waitDone(); }
virtual bool sendMessage(MessageQueue::Element msg, MessageQueue::BlockType block_type);
virtual MessageQueue::Element recvMessage(MessageQueue::BlockType block_type);
virtual const MessageQueue& getMessageQueue() const { return mMessageQueue; }
virtual bool start();
virtual void quit(bool is_jam);
virtual void waitDone();
virtual void quitAndDestroySingleThread(bool is_jam) { quitAndWaitDoneSingleThread(is_jam); }
virtual void quitAndWaitDoneSingleThread(bool is_jam);
virtual void setPriority(s32 prio);
virtual s32 getPriority() const;
virtual MessageQueue::BlockType getBlockType() const { return mBlockType; }
virtual s32 getStackSize() const { return mStackSize; }
virtual s32 calcStackUsedSizePeak() const;
u32 getId() const { return mId; }
State getState() const { return mState; }
bool isDone() const { return mState == State::cTerminated || mState == State::cReleased; }
bool isActive() const { return mState == State::cRunning || mState == State::cQuitting; }
const CoreIdMask& getAffinity() const { return mAffinity; }
void setAffinity(const CoreIdMask& affinity);
static void yield();
static void sleep(TickSpan howLong);
void checkStackOverFlow(const char* source_file, s32 source_line) const;
void checkStackEndCorruption(const char* source_file, s32 source_line) const;
void checkStackPointerOverFlow(const char* source_file, s32 source_line) const;
void setStackOverflowExceptionEnable(bool);
ThreadListNode* getThreadListNode() { return &mListNode; }
#ifdef SEAD_DEBUG
void listenPropertyEvent(const hostio::PropertyEvent* event) override;
void genMessage(hostio::Context* context) override;
#endif
bool isDefaultPriority() const { return getPriority() == cDefaultPriority; }
static const s32 cDefaultPriority;
protected:
#ifdef NNSDK
Thread(Heap* heap, nn::os::ThreadType*, u32);
#endif
virtual void run_();
virtual void calc_(MessageQueue::Element msg) = 0;
virtual uintptr_t getStackCheckStartAddress_() const;
void initStackCheck_();
void initStackCheckWithCurrentStackPointer_();
#ifdef NNSDK
static void ninThreadFunc_(void*);
#endif
MessageQueue mMessageQueue;
s32 mStackSize = 0;
ThreadListNode mListNode;
Heap* mCurrentHeap = nullptr;
FindContainHeapCache mFindContainHeapCache;
MessageQueue::BlockType mBlockType = MessageQueue::BlockType::Blocking;
MessageQueue::Element mQuitMsg = 0;
u32 mId = 0;
State mState = State::cInitialized;
CoreIdMask mAffinity{CoreId::cMain};
#ifdef NNSDK
nn::os::ThreadType* mThreadInner = nullptr;
#endif
void* mStackTop = nullptr;
void* mStackTopForCheck = nullptr;
s32 mPriority = 0;
};
class ThreadMgr : public hostio::Node
{
SEAD_SINGLETON_DISPOSER(ThreadMgr)
public:
ThreadMgr();
virtual ~ThreadMgr();
void initialize(Heap* heap);
void destroy();
bool isMainThread() const;
Thread* getMainThread() const { return mMainThread; }
Thread* getCurrentThread() const { return reinterpret_cast<Thread*>(mThreadPtrTLS.getValue()); }
static void waitDoneMultipleThread(Thread* const* threads, s32 num);
static void quitAndWaitDoneMultipleThread(Thread** threads, s32 num, bool is_jam);
static void checkCurrentThreadStackOverFlow(const char* source_file, s32 source_line);
static void checkCurrentThreadStackEndCorruption(const char* source_file, s32 source_line);
static void checkCurrentThreadStackPointerOverFlow(const char* source_file, s32 source_line);
CriticalSection* getListCS() { return &mListCS; }
#ifdef SEAD_DEBUG
void initHostIO();
void genMessage(hostio::Context* context) override;
void listenPropertyEvent(const hostio::PropertyEvent* event) override;
#endif
protected:
friend class Thread;
void addThread_(Thread* thread)
{
ScopedLock<CriticalSection> lock(getListCS());
mList.pushBack(thread->getThreadListNode());
}
void removeThread_(Thread* thread)
{
ScopedLock<CriticalSection> lock(getListCS());
mList.erase(thread->getThreadListNode());
}
void initMainThread_(Heap* heap);
void destroyMainThread_();
static u32 getCurrentThreadID_();
private:
ThreadList mList;
CriticalSection mListCS;
Thread* mMainThread = nullptr;
ThreadLocalStorage mThreadPtrTLS;
};
class MainThread : public Thread
{
public:
#ifdef NNSDK
MainThread(Heap* heap, nn::os::ThreadType* nn_thread, u32 thread_id)
: Thread(heap, nn_thread, thread_id)
{
}
#endif
~MainThread() override { mState = State::cTerminated; }
void destroy() override { SEAD_ASSERT_MSG(false, "Main thread can not destroy"); }
void quit(bool) override { SEAD_ASSERT_MSG(false, "Main thread can not quit"); }
void waitDone() override { SEAD_ASSERT_MSG(false, "Main thread can not waitDone"); }
void quitAndDestroySingleThread(bool) override
{
SEAD_ASSERT_MSG(false, "Main thread can not quit");
}
void setPriority(s32) override { SEAD_ASSERT_MSG(false, "Main thread can not set priority"); }
protected:
void calc_(MessageQueue::Element) override {}
};
} // namespace sead
@@ -0,0 +1,36 @@
#pragma once
#ifdef NNSDK
#include <nn/os.h>
#endif
#include "basis/seadTypes.h"
namespace sead
{
class ThreadLocalStorage
{
public:
ThreadLocalStorage();
~ThreadLocalStorage();
ThreadLocalStorage(const ThreadLocalStorage&) = delete;
ThreadLocalStorage& operator=(const ThreadLocalStorage&) = delete;
void setValue(uintptr_t value);
uintptr_t getValue() const;
private:
#ifdef NNSDK
nn::os::TlsSlot mTlsSlot;
#endif
};
} // namespace sead
#define SEAD_THREAD_THREAD_LOCAL_STORAGE_H_
#ifdef NNSDK
#include "thread/nin/seadThreadLocalStorageNin.hpp"
#else
#error "Unknown platform"
#endif
#undef SEAD_THREAD_THREAD_LOCAL_STORAGE_H_
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include "basis/seadTypes.h"
namespace sead
{
class ThreadUtil
{
public:
static s32 ConvertPrioritySeadToPlatform(s32 prio);
static s32 ConvertPriorityPlatformToSead(s32 prio);
static uintptr_t GetCurrentStackPointer();
};
} // namespace sead