os: refactor multi wait apis to better match Nintendo's latest implementation

This commit is contained in:
Michael Scire 2022-04-12 16:47:36 -07:00
parent b45671fd35
commit 02b126c2be
23 changed files with 309 additions and 243 deletions

View file

@ -30,46 +30,50 @@ namespace ams::os::impl {
public: public:
/* Gets whether the held object is currently signaled. */ /* Gets whether the held object is currently signaled. */
virtual TriBool IsSignaled() const = 0; virtual TriBool IsSignaled() const = 0;
/* Adds to multi wait's object list, returns is signaled. */ /* Adds to multi wait's object list, returns is signaled. */
virtual TriBool LinkToObjectList() = 0; virtual TriBool AddToObjectList() = 0;
/* Removes from the multi wait's object list. */ /* Removes from the multi wait's object list. */
virtual void UnlinkFromObjectList() = 0; virtual void RemoveFromObjectList() = 0;
/* Gets handle to output, returns os::InvalidNativeHandle on failure. */
virtual NativeHandle GetHandle() const = 0; /* Gets whether waitable has a native handle, writes to output if it does. */
virtual bool GetNativeHandle(os::NativeHandle *) const = 0;
/* Gets the amount of time remaining until this wakes up. */ /* Gets the amount of time remaining until this wakes up. */
virtual TimeSpan GetAbsoluteWakeupTime() const { virtual TimeSpan GetAbsoluteTimeToWakeup() const {
return TimeSpan::FromNanoSeconds(std::numeric_limits<s64>::max()); return TimeSpan::FromNanoSeconds(std::numeric_limits<s64>::max());
} }
/* Interface with multi wait. */ /* Interface with multi wait. */
void SetMultiWait(MultiWaitImpl *m) { ALWAYS_INLINE void SetMultiWait(MultiWaitImpl *m) {
m_multi_wait = m; m_multi_wait = m;
} }
MultiWaitImpl *GetMultiWait() const { ALWAYS_INLINE MultiWaitImpl *GetMultiWait() const {
return m_multi_wait; return m_multi_wait;
} }
bool IsLinked() const { ALWAYS_INLINE bool IsLinked() const { return m_multi_wait != nullptr; }
return m_multi_wait != nullptr; ALWAYS_INLINE bool IsNotLinked() const { return m_multi_wait == nullptr; }
}
}; };
class MultiWaitHolderOfUserObject : public MultiWaitHolderBase { class MultiWaitHolderOfUserWaitObject : public MultiWaitHolderBase {
public: public:
/* All user objects have no handle to wait on. */ /* All user objects have no handle to wait on. */
virtual NativeHandle GetHandle() const override final { virtual bool GetNativeHandle(os::NativeHandle *) const override final {
return os::InvalidNativeHandle; return false;
} }
}; };
class MultiWaitHolderOfKernelObject : public MultiWaitHolderBase { class MultiWaitHolderOfNativeWaitObject : public MultiWaitHolderBase {
public: public:
/* All kernel objects have native handles, and thus don't have object list semantics. */ /* All native objects have native handles, and thus don't have object list semantics. */
virtual TriBool LinkToObjectList() override final { virtual TriBool AddToObjectList() override final {
return TriBool::Undefined; return TriBool::Undefined;
} }
virtual void UnlinkFromObjectList() override final {
virtual void RemoveFromObjectList() override final {
/* ... */ /* ... */
} }
}; };

View file

@ -14,7 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "os_multiple_wait_holder_of_handle.hpp" #include "os_multiple_wait_holder_of_native_handle.hpp"
#include "os_multiple_wait_holder_of_event.hpp" #include "os_multiple_wait_holder_of_event.hpp"
#include "os_multiple_wait_holder_of_inter_process_event.hpp" #include "os_multiple_wait_holder_of_inter_process_event.hpp"
#include "os_multiple_wait_holder_of_interrupt_event.hpp" #include "os_multiple_wait_holder_of_interrupt_event.hpp"
@ -27,30 +27,30 @@ namespace ams::os::impl {
struct MultiWaitHolderImpl { struct MultiWaitHolderImpl {
union { union {
util::TypedStorage<MultiWaitHolderOfHandle> holder_of_handle_storage; util::TypedStorage<MultiWaitHolderOfNativeHandle> holder_of_native_handle_storage;
util::TypedStorage<MultiWaitHolderOfEvent> holder_of_event_storage; util::TypedStorage<MultiWaitHolderOfEvent> holder_of_event_storage;
util::TypedStorage<MultiWaitHolderOfInterProcessEvent> holder_of_inter_process_event_storage; util::TypedStorage<MultiWaitHolderOfInterProcessEvent> holder_of_inter_process_event_storage;
util::TypedStorage<MultiWaitHolderOfInterruptEvent> holder_of_interrupt_event_storage; util::TypedStorage<MultiWaitHolderOfInterruptEvent> holder_of_interrupt_event_storage;
util::TypedStorage<MultiWaitHolderOfTimerEvent> holder_of_timer_event_storage; util::TypedStorage<MultiWaitHolderOfTimerEvent> holder_of_timer_event_storage;
util::TypedStorage<MultiWaitHolderOfThread> holder_of_thread_storage; util::TypedStorage<MultiWaitHolderOfThread> holder_of_thread_storage;
util::TypedStorage<MultiWaitHolderOfSemaphore> holder_of_semaphore_storage; util::TypedStorage<MultiWaitHolderOfSemaphore> holder_of_semaphore_storage;
util::TypedStorage<MultiWaitHolderOfMessageQueueForNotFull> holder_of_mq_for_not_full_storage; util::TypedStorage<MultiWaitHolderOfMessageQueueNotFull> holder_of_mq_not_full_storage;
util::TypedStorage<MultiWaitHolderOfMessageQueueForNotEmpty> holder_of_mq_for_not_empty_storage; util::TypedStorage<MultiWaitHolderOfMessageQueueNotEmpty> holder_of_mq_not_empty_storage;
}; };
}; };
#define CHECK_HOLDER(T) \ #define CHECK_HOLDER(T) \
static_assert(std::is_base_of<::ams::os::impl::MultiWaitHolderBase, T>::value && std::is_trivially_destructible<T>::value, #T) static_assert(std::is_base_of<::ams::os::impl::MultiWaitHolderBase, T>::value && std::is_trivially_destructible<T>::value, #T)
CHECK_HOLDER(MultiWaitHolderOfHandle); CHECK_HOLDER(MultiWaitHolderOfNativeHandle);
CHECK_HOLDER(MultiWaitHolderOfEvent); CHECK_HOLDER(MultiWaitHolderOfEvent);
CHECK_HOLDER(MultiWaitHolderOfInterProcessEvent); CHECK_HOLDER(MultiWaitHolderOfInterProcessEvent);
CHECK_HOLDER(MultiWaitHolderOfInterruptEvent); CHECK_HOLDER(MultiWaitHolderOfInterruptEvent);
CHECK_HOLDER(MultiWaitHolderOfTimerEvent); CHECK_HOLDER(MultiWaitHolderOfTimerEvent);
CHECK_HOLDER(MultiWaitHolderOfThread); CHECK_HOLDER(MultiWaitHolderOfThread);
CHECK_HOLDER(MultiWaitHolderOfSemaphore); CHECK_HOLDER(MultiWaitHolderOfSemaphore);
CHECK_HOLDER(MultiWaitHolderOfMessageQueueForNotFull); CHECK_HOLDER(MultiWaitHolderOfMessageQueueNotFull);
CHECK_HOLDER(MultiWaitHolderOfMessageQueueForNotEmpty); CHECK_HOLDER(MultiWaitHolderOfMessageQueueNotEmpty);
#undef CHECK_HOLDER #undef CHECK_HOLDER

View file

@ -19,11 +19,11 @@
namespace ams::os::impl { namespace ams::os::impl {
class MultiWaitHolderOfEvent : public MultiWaitHolderOfUserObject { class MultiWaitHolderOfEvent : public MultiWaitHolderOfUserWaitObject {
private: private:
EventType *m_event; EventType *m_event;
private: private:
TriBool IsSignaledImpl() const { ALWAYS_INLINE TriBool IsSignaledUnsafe() const {
return m_event->signaled ? TriBool::True : TriBool::False; return m_event->signaled ? TriBool::True : TriBool::False;
} }
public: public:
@ -32,20 +32,20 @@ namespace ams::os::impl {
/* IsSignaled, Link, Unlink implemented. */ /* IsSignaled, Link, Unlink implemented. */
virtual TriBool IsSignaled() const override { virtual TriBool IsSignaled() const override {
std::scoped_lock lk(GetReference(m_event->cs_event)); std::scoped_lock lk(GetReference(m_event->cs_event));
return this->IsSignaledImpl(); return this->IsSignaledUnsafe();
} }
virtual TriBool LinkToObjectList() override { virtual TriBool AddToObjectList() override {
std::scoped_lock lk(GetReference(m_event->cs_event)); std::scoped_lock lk(GetReference(m_event->cs_event));
GetReference(m_event->multi_wait_object_list_storage).LinkMultiWaitHolder(*this); GetReference(m_event->multi_wait_object_list_storage).PushBackToList(*this);
return this->IsSignaledImpl(); return this->IsSignaledUnsafe();
} }
virtual void UnlinkFromObjectList() override { virtual void RemoveFromObjectList() override {
std::scoped_lock lk(GetReference(m_event->cs_event)); std::scoped_lock lk(GetReference(m_event->cs_event));
GetReference(m_event->multi_wait_object_list_storage).UnlinkMultiWaitHolder(*this); GetReference(m_event->multi_wait_object_list_storage).EraseFromList(*this);
} }
}; };

View file

@ -19,7 +19,7 @@
namespace ams::os::impl { namespace ams::os::impl {
class MultiWaitHolderOfInterProcessEvent : public MultiWaitHolderOfKernelObject { class MultiWaitHolderOfInterProcessEvent : public MultiWaitHolderOfNativeWaitObject {
private: private:
InterProcessEventType *m_event; InterProcessEventType *m_event;
public: public:
@ -30,8 +30,9 @@ namespace ams::os::impl {
return TriBool::Undefined; return TriBool::Undefined;
} }
virtual NativeHandle GetHandle() const override { virtual bool GetNativeHandle(os::NativeHandle *out) const override {
return m_event->readable_handle; *out = m_event->readable_handle;
return true;
} }
}; };

View file

@ -19,8 +19,9 @@
namespace ams::os::impl { namespace ams::os::impl {
NativeHandle MultiWaitHolderOfInterruptEvent::GetHandle() const { bool MultiWaitHolderOfInterruptEvent::GetNativeHandle(os::NativeHandle *out) const {
return GetReference(m_event->impl).GetHandle(); *out = GetReference(m_event->impl).GetHandle();
return true;
} }
} }

View file

@ -18,7 +18,7 @@
namespace ams::os::impl { namespace ams::os::impl {
class MultiWaitHolderOfInterruptEvent : public MultiWaitHolderOfKernelObject { class MultiWaitHolderOfInterruptEvent : public MultiWaitHolderOfNativeWaitObject {
private: private:
InterruptEventType *m_event; InterruptEventType *m_event;
public: public:
@ -29,7 +29,7 @@ namespace ams::os::impl {
return TriBool::Undefined; return TriBool::Undefined;
} }
virtual NativeHandle GetHandle() const override; virtual bool GetNativeHandle(os::NativeHandle *out) const override;
}; };
} }

View file

@ -19,57 +19,64 @@
namespace ams::os::impl { namespace ams::os::impl {
template<MessageQueueWaitType WaitType> class MultiWaitHolderOfMessageQueueNotEmpty : public MultiWaitHolderOfUserWaitObject {
class MultiWaitHolderOfMessageQueue : public MultiWaitHolderOfUserObject {
static_assert(WaitType == MessageQueueWaitType::ForNotEmpty || WaitType == MessageQueueWaitType::ForNotFull);
private: private:
MessageQueueType *m_mq; MessageQueueType *m_mq;
private: private:
constexpr inline TriBool IsSignaledImpl() const { ALWAYS_INLINE TriBool IsSignaledUnsafe() const {
if constexpr (WaitType == MessageQueueWaitType::ForNotEmpty) { return m_mq->count > 0 ? TriBool::True : TriBool::False;
/* ForNotEmpty. */
return m_mq->count > 0 ? TriBool::True : TriBool::False;
} else if constexpr (WaitType == MessageQueueWaitType::ForNotFull) {
/* ForNotFull */
return m_mq->count < m_mq->capacity ? TriBool::True : TriBool::False;
} else {
static_assert(WaitType != WaitType);
}
}
constexpr inline MultiWaitObjectList &GetObjectList() const {
if constexpr (WaitType == MessageQueueWaitType::ForNotEmpty) {
return GetReference(m_mq->waitlist_not_empty);
} else if constexpr (WaitType == MessageQueueWaitType::ForNotFull) {
return GetReference(m_mq->waitlist_not_full);
} else {
static_assert(WaitType != WaitType);
}
} }
public: public:
explicit MultiWaitHolderOfMessageQueue(MessageQueueType *mq) : m_mq(mq) { /* ... */ } explicit MultiWaitHolderOfMessageQueueNotEmpty(MessageQueueType *mq) : m_mq(mq) { /* ... */ }
/* IsSignaled, Link, Unlink implemented. */ /* IsSignaled, Link, Unlink implemented. */
virtual TriBool IsSignaled() const override { virtual TriBool IsSignaled() const override {
std::scoped_lock lk(GetReference(m_mq->cs_queue)); std::scoped_lock lk(GetReference(m_mq->cs_queue));
return this->IsSignaledImpl(); return this->IsSignaledUnsafe();
} }
virtual TriBool LinkToObjectList() override { virtual TriBool AddToObjectList() override {
std::scoped_lock lk(GetReference(m_mq->cs_queue)); std::scoped_lock lk(GetReference(m_mq->cs_queue));
this->GetObjectList().LinkMultiWaitHolder(*this); GetReference(m_mq->waitlist_not_empty).PushBackToList(*this);
return this->IsSignaledImpl(); return this->IsSignaledUnsafe();
} }
virtual void UnlinkFromObjectList() override { virtual void RemoveFromObjectList() override {
std::scoped_lock lk(GetReference(m_mq->cs_queue)); std::scoped_lock lk(GetReference(m_mq->cs_queue));
this->GetObjectList().UnlinkMultiWaitHolder(*this); GetReference(m_mq->waitlist_not_empty).EraseFromList(*this);
} }
}; };
using MultiWaitHolderOfMessageQueueForNotEmpty = MultiWaitHolderOfMessageQueue<MessageQueueWaitType::ForNotEmpty>; class MultiWaitHolderOfMessageQueueNotFull : public MultiWaitHolderOfUserWaitObject {
using MultiWaitHolderOfMessageQueueForNotFull = MultiWaitHolderOfMessageQueue<MessageQueueWaitType::ForNotFull>; private:
MessageQueueType *m_mq;
private:
ALWAYS_INLINE TriBool IsSignaledUnsafe() const {
return m_mq->count < m_mq->capacity ? TriBool::True : TriBool::False;
}
public:
explicit MultiWaitHolderOfMessageQueueNotFull(MessageQueueType *mq) : m_mq(mq) { /* ... */ }
/* IsSignaled, Link, Unlink implemented. */
virtual TriBool IsSignaled() const override {
std::scoped_lock lk(GetReference(m_mq->cs_queue));
return this->IsSignaledUnsafe();
}
virtual TriBool AddToObjectList() override {
std::scoped_lock lk(GetReference(m_mq->cs_queue));
GetReference(m_mq->waitlist_not_full).PushBackToList(*this);
return this->IsSignaledUnsafe();
}
virtual void RemoveFromObjectList() override {
std::scoped_lock lk(GetReference(m_mq->cs_queue));
GetReference(m_mq->waitlist_not_full).EraseFromList(*this);
}
};
} }

View file

@ -18,19 +18,20 @@
namespace ams::os::impl { namespace ams::os::impl {
class MultiWaitHolderOfHandle : public MultiWaitHolderOfKernelObject { class MultiWaitHolderOfNativeHandle : public MultiWaitHolderOfNativeWaitObject {
private: private:
NativeHandle m_handle; NativeHandle m_handle;
public: public:
explicit MultiWaitHolderOfHandle(NativeHandle h) : m_handle(h) { /* ... */ } explicit MultiWaitHolderOfNativeHandle(NativeHandle h) : m_handle(h) { /* ... */ }
/* IsSignaled, GetHandle both implemented. */ /* IsSignaled, GetHandle both implemented. */
virtual TriBool IsSignaled() const override { virtual TriBool IsSignaled() const override {
return TriBool::Undefined; return TriBool::Undefined;
} }
virtual NativeHandle GetHandle() const override { virtual bool GetNativeHandle(os::NativeHandle *out) const override {
return m_handle; *out = m_handle;
return true;
} }
}; };

View file

@ -19,7 +19,7 @@
namespace ams::os::impl { namespace ams::os::impl {
class MultiWaitHolderOfSemaphore : public MultiWaitHolderOfUserObject { class MultiWaitHolderOfSemaphore : public MultiWaitHolderOfUserWaitObject {
private: private:
SemaphoreType *m_semaphore; SemaphoreType *m_semaphore;
private: private:
@ -35,17 +35,17 @@ namespace ams::os::impl {
return this->IsSignaledImpl(); return this->IsSignaledImpl();
} }
virtual TriBool LinkToObjectList() override { virtual TriBool AddToObjectList() override {
std::scoped_lock lk(GetReference(m_semaphore->cs_sema)); std::scoped_lock lk(GetReference(m_semaphore->cs_sema));
GetReference(m_semaphore->waitlist).LinkMultiWaitHolder(*this); GetReference(m_semaphore->waitlist).PushBackToList(*this);
return this->IsSignaledImpl(); return this->IsSignaledImpl();
} }
virtual void UnlinkFromObjectList() override { virtual void RemoveFromObjectList() override {
std::scoped_lock lk(GetReference(m_semaphore->cs_sema)); std::scoped_lock lk(GetReference(m_semaphore->cs_sema));
GetReference(m_semaphore->waitlist).UnlinkMultiWaitHolder(*this); GetReference(m_semaphore->waitlist).EraseFromList(*this);
} }
}; };

View file

@ -18,7 +18,7 @@
namespace ams::os::impl { namespace ams::os::impl {
class MultiWaitHolderOfThread : public MultiWaitHolderOfUserObject { class MultiWaitHolderOfThread : public MultiWaitHolderOfUserWaitObject {
private: private:
ThreadType *m_thread; ThreadType *m_thread;
private: private:
@ -34,17 +34,17 @@ namespace ams::os::impl {
return this->IsSignaledImpl(); return this->IsSignaledImpl();
} }
virtual TriBool LinkToObjectList() override { virtual TriBool AddToObjectList() override {
std::scoped_lock lk(GetReference(m_thread->cs_thread)); std::scoped_lock lk(GetReference(m_thread->cs_thread));
GetReference(m_thread->waitlist).LinkMultiWaitHolder(*this); GetReference(m_thread->waitlist).PushBackToList(*this);
return this->IsSignaledImpl(); return this->IsSignaledImpl();
} }
virtual void UnlinkFromObjectList() override { virtual void RemoveFromObjectList() override {
std::scoped_lock lk(GetReference(m_thread->cs_thread)); std::scoped_lock lk(GetReference(m_thread->cs_thread));
GetReference(m_thread->waitlist).UnlinkMultiWaitHolder(*this); GetReference(m_thread->waitlist).EraseFromList(*this);
} }
}; };

View file

@ -21,13 +21,15 @@
namespace ams::os::impl { namespace ams::os::impl {
class MultiWaitHolderOfTimerEvent : public MultiWaitHolderOfUserObject { class MultiWaitHolderOfTimerEvent : public MultiWaitHolderOfUserWaitObject {
private: private:
TimerEventType *m_event; TimerEventType *m_event;
private: private:
TriBool IsSignaledImpl() const { TriBool IsSignaledUnsafe() const {
TimeSpan cur_time = this->GetMultiWait()->GetCurrentTime(); TimeSpan cur_time = this->GetMultiWait()->GetCurrTime();
UpdateSignalStateAndRecalculateNextTimeToWakeupUnsafe(m_event, cur_time);
os::impl::UpdateSignalStateAndRecalcNextTimeToWakeupUnsafe(m_event, cur_time);
return m_event->signaled ? TriBool::True : TriBool::False; return m_event->signaled ? TriBool::True : TriBool::False;
} }
public: public:
@ -36,31 +38,30 @@ namespace ams::os::impl {
/* IsSignaled, Link, Unlink implemented. */ /* IsSignaled, Link, Unlink implemented. */
virtual TriBool IsSignaled() const override { virtual TriBool IsSignaled() const override {
std::scoped_lock lk(GetReference(m_event->cs_timer_event)); std::scoped_lock lk(GetReference(m_event->cs_timer_event));
return this->IsSignaledImpl();
return this->IsSignaledUnsafe();
} }
virtual TriBool LinkToObjectList() override { virtual TriBool AddToObjectList() override {
std::scoped_lock lk(GetReference(m_event->cs_timer_event)); std::scoped_lock lk(GetReference(m_event->cs_timer_event));
GetReference(m_event->multi_wait_object_list_storage).LinkMultiWaitHolder(*this); GetReference(m_event->multi_wait_object_list_storage).PushBackToList(*this);
return this->IsSignaledImpl();
return this->IsSignaledUnsafe();
} }
virtual void UnlinkFromObjectList() override { virtual void RemoveFromObjectList() override {
std::scoped_lock lk(GetReference(m_event->cs_timer_event)); std::scoped_lock lk(GetReference(m_event->cs_timer_event));
GetReference(m_event->multi_wait_object_list_storage).UnlinkMultiWaitHolder(*this); GetReference(m_event->multi_wait_object_list_storage).EraseFromList(*this);
} }
/* Gets the amount of time remaining until this wakes up. */ /* Gets the amount of time remaining until this wakes up. */
virtual TimeSpan GetAbsoluteWakeupTime() const override { virtual TimeSpan GetAbsoluteTimeToWakeup() const override {
std::scoped_lock lk(GetReference(m_event->cs_timer_event)); std::scoped_lock lk(GetReference(m_event->cs_timer_event));
if (m_event->timer_state == TimerEventType::TimerState_Stop) { return m_event->timer_state != TimerEventType::TimerState_Stop ? GetReference(m_event->next_time_to_wakeup)
return TimeSpan::FromNanoSeconds(std::numeric_limits<s64>::max()); : TimeSpan::FromNanoSeconds(std::numeric_limits<s64>::max());
}
return GetReference(m_event->next_time_to_wakeup);
} }
}; };

View file

@ -20,149 +20,194 @@
namespace ams::os::impl { namespace ams::os::impl {
Result MultiWaitImpl::WaitAnyImpl(MultiWaitHolderBase **out, bool infinite, TimeSpan timeout, bool reply, NativeHandle reply_target) { template<bool AllowReply>
Result MultiWaitImpl::WaitAnyImpl(MultiWaitHolderBase **out, bool infinite, TimeSpan timeout, NativeHandle reply_target) {
/* Prepare for processing. */ /* Prepare for processing. */
m_signaled_holder = nullptr; m_signaled_holder = nullptr;
m_target_impl.SetCurrentThreadHandleForCancelWait(); m_target_impl.SetCurrentThreadHandleForCancelWait();
MultiWaitHolderBase *holder = this->LinkHoldersToObjectList();
/* When we're done, cleanup and set output. */ /* Add each holder to the object list, and try to find one that's signaled. */
ON_SCOPE_EXIT { MultiWaitHolderBase *signaled_holder = this->AddToEachObjectListAndCheckObjectState();
/* Unlink holders from the current object list. */
this->UnlinkHoldersFromObjectList();
/* Clear cancel wait. */
m_target_impl.ClearCurrentThreadHandleForCancelWait();
/* Set output holder. */
*out = holder;
};
/* Check if we've been signaled. */ /* Check if we've been signaled. */
{ {
std::scoped_lock lk(m_cs_wait); std::scoped_lock lk(m_cs_wait);
if (m_signaled_holder != nullptr) { if (m_signaled_holder != nullptr) {
holder = m_signaled_holder; signaled_holder = m_signaled_holder;
} }
} }
/* Process object array. */ /* Process object array. */
if (holder != nullptr) { if (signaled_holder != nullptr) {
R_SUCCEED_IF(!(reply && reply_target != os::InvalidNativeHandle)); /* If we have a signaled holder and we're allowed to reply, try to do so. */
if constexpr (AllowReply) {
ON_RESULT_FAILURE { holder = nullptr; }; /* Try to reply to the reply target. */
if (reply_target != os::InvalidNativeHandle) {
s32 index; s32 index;
R_RETURN(m_target_impl.TimedReplyAndReceive(std::addressof(index), nullptr, 0, 0, reply_target, TimeSpan::FromNanoSeconds(0))) R_TRY(m_target_impl.TimedReplyAndReceive(std::addressof(index), nullptr, 0, 0, reply_target, TimeSpan::FromNanoSeconds(0)));
}
}
} else { } else {
R_RETURN(this->WaitAnyHandleImpl(std::addressof(holder), infinite, timeout, reply, reply_target)); /* If there's no signaled holder, wait for one to be signaled. */
R_TRY(this->InternalWaitAnyImpl<AllowReply>(std::addressof(signaled_holder), infinite, timeout, reply_target));
} }
/* Remove each holder from the current object list. */
this->RemoveFromEachObjectList();
/* Clear cancel wait. */
m_target_impl.ClearCurrentThreadHandleForCancelWait();
/* Set output holder. */
*out = signaled_holder;
R_SUCCEED();
} }
Result MultiWaitImpl::WaitAnyHandleImpl(MultiWaitHolderBase **out, bool infinite, TimeSpan timeout, bool reply, NativeHandle reply_target) { template<bool AllowReply>
Result MultiWaitImpl::InternalWaitAnyImpl(MultiWaitHolderBase **out, bool infinite, TimeSpan timeout, NativeHandle reply_target) {
/* Build the objects array. */
NativeHandle object_handles[MaximumHandleCount]; NativeHandle object_handles[MaximumHandleCount];
MultiWaitHolderBase *objects[MaximumHandleCount]; MultiWaitHolderBase *objects[MaximumHandleCount];
const s32 count = this->BuildHandleArray(object_handles, objects, MaximumHandleCount); const s32 count = this->ConstructObjectsArray(object_handles, objects, MaximumHandleCount);
const TimeSpan end_time = infinite ? TimeSpan::FromNanoSeconds(std::numeric_limits<s64>::max()) : GetCurrentTick().ToTimeSpan() + timeout;
/* Determine the appropriate end time for our wait. */
const TimeSpan end_time = infinite ? TimeSpan::FromNanoSeconds(std::numeric_limits<s64>::max()) : os::impl::GetCurrentTick().ToTimeSpan() + timeout;
/* Loop, waiting until we're done. */
while (true) { while (true) {
m_current_time = GetCurrentTick().ToTimeSpan(); /* Update the current time for our loop. */
m_current_time = os::impl::GetCurrentTick().ToTimeSpan();
/* Determine which object has the minimum wakeup time. */
TimeSpan min_timeout = 0; TimeSpan min_timeout = 0;
MultiWaitHolderBase *min_timeout_object = this->RecalculateNextTimeout(std::addressof(min_timeout), end_time); MultiWaitHolderBase *min_timeout_object = this->RecalcMultiWaitTimeout(std::addressof(min_timeout), end_time);
s32 index = WaitInvalid; /* Perform the wait using native apis. */
s32 index = WaitInvalid;
Result wait_result = ResultSuccess(); Result wait_result = ResultSuccess();
if (reply) { if (infinite && min_timeout_object == nullptr) {
if (infinite && min_timeout_object == nullptr) { /* If we're performing an infinite wait, just do the appropriate wait or reply/receive. */
if constexpr (AllowReply) {
wait_result = m_target_impl.ReplyAndReceive(std::addressof(index), object_handles, MaximumHandleCount, count, reply_target); wait_result = m_target_impl.ReplyAndReceive(std::addressof(index), object_handles, MaximumHandleCount, count, reply_target);
} else { } else {
wait_result = m_target_impl.TimedReplyAndReceive(std::addressof(index), object_handles, MaximumHandleCount, count, reply_target, min_timeout); wait_result = m_target_impl.WaitAny(std::addressof(index), object_handles, MaximumHandleCount, count);
} }
} else if (infinite && min_timeout_object == nullptr) {
wait_result = m_target_impl.WaitAny(std::addressof(index), object_handles, MaximumHandleCount, count);
} else { } else {
if (count == 0 && min_timeout == 0) { /* We need to do our wait with a timeout. */
index = WaitTimedOut; if constexpr (AllowReply) {
wait_result = m_target_impl.TimedReplyAndReceive(std::addressof(index), object_handles, MaximumHandleCount, count, reply_target, min_timeout);
} else { } else {
wait_result = m_target_impl.TimedWaitAny(std::addressof(index), object_handles, MaximumHandleCount, count, min_timeout); if (count != 0 || min_timeout != 0) {
AMS_ABORT_UNLESS(index != WaitInvalid); wait_result = m_target_impl.TimedWaitAny(std::addressof(index), object_handles, MaximumHandleCount, count, min_timeout);
} else {
index = WaitTimedOut;
}
} }
} }
if (index == WaitInvalid) { /* Process the result of our wait. */
*out = nullptr;
R_RETURN(wait_result);
}
switch (index) { switch (index) {
case WaitTimedOut: case WaitInvalid:
if (min_timeout_object) { /* If an invalid wait was performed, just return no signaled holder. */
m_current_time = GetCurrentTick().ToTimeSpan(); {
if (min_timeout_object->IsSignaled() == TriBool::True) {
std::scoped_lock lk(m_cs_wait);
m_signaled_holder = min_timeout_object;
*out = min_timeout_object;
R_RETURN(wait_result);
}
} else {
*out = nullptr; *out = nullptr;
R_RETURN(wait_result); R_RETURN(wait_result);
} }
break; break;
case WaitCancelled: case WaitCancelled:
/* If the wait was canceled, it might be because a non-native waitable was signaled. Check and return it, if this is the case. */
{ {
std::scoped_lock lk(m_cs_wait); std::scoped_lock lk(m_cs_wait);
if (m_signaled_holder) { if (m_signaled_holder) {
*out = m_signaled_holder; *out = m_signaled_holder;
R_RETURN(wait_result); R_RETURN(wait_result);
} }
} }
break; break;
case WaitTimedOut:
/* If we timed out, this might have been because a timer is now signaled. */
if (min_timeout_object != nullptr) {
/* Update our current time. */
m_current_time = GetCurrentTick().ToTimeSpan();
/* Check if the minimum timeout object is now signaled. */
if (min_timeout_object->IsSignaled() == TriBool::True) {
std::scoped_lock lk(m_cs_wait);
/* Set our signaled holder (and the output) as the newly signaled minimum timeout object. */
m_signaled_holder = min_timeout_object;
*out = min_timeout_object;
R_RETURN(wait_result);
}
} else {
/* If we have no minimum timeout object but we timed out, just return no signaled holder. */
*out = nullptr;
R_RETURN(wait_result);
}
break;
default: /* 0 - 0x3F, valid. */ default: /* 0 - 0x3F, valid. */
{ {
if constexpr (MaximumHandleCount > 0) { /* Sanity check that the returned index is within the range of our objects array. */
AMS_ASSERT(0 <= index && index < static_cast<s32>(MaximumHandleCount)); AMS_ASSERT(0 <= index && index < count);
std::scoped_lock lk(m_cs_wait); std::scoped_lock lk(m_cs_wait);
m_signaled_holder = objects[index];
*out = objects[index]; /* Set our signaled holder (and the output) as the newly signaled object. */
R_RETURN(wait_result); m_signaled_holder = objects[index];
} else { *out = objects[index];
AMS_ABORT_UNLESS(MaximumHandleCount > 0); R_RETURN(wait_result);
}
} }
break; break;
} }
reply_target = os::InvalidNativeHandle; /* We're going to be looping again; prevent ourselves from replying to the same object twice. */
if constexpr (AllowReply) {
reply_target = os::InvalidNativeHandle;
}
} }
} }
s32 MultiWaitImpl::BuildHandleArray(NativeHandle out_handles[], MultiWaitHolderBase *out_objects[], s32 num) { MultiWaitHolderBase *MultiWaitImpl::WaitAnyImpl(bool infinite, TimeSpan timeout) {
MultiWaitHolderBase *holder = nullptr;
const Result wait_result = this->WaitAnyImpl<false>(std::addressof(holder), infinite, timeout, os::InvalidNativeHandle);
R_ASSERT(wait_result);
AMS_UNUSED(wait_result);
return holder;
}
Result MultiWaitImpl::ReplyAndReceive(MultiWaitHolderBase **out, NativeHandle reply_target) {
R_RETURN(this->WaitAnyImpl<true>(out, true, TimeSpan::FromNanoSeconds(std::numeric_limits<s64>::max()), reply_target));
}
s32 MultiWaitImpl::ConstructObjectsArray(NativeHandle out_handles[], MultiWaitHolderBase *out_objects[], s32 num) {
/* Add all objects with a native handle to the output array. */
s32 count = 0; s32 count = 0;
for (MultiWaitHolderBase &holder_base : m_multi_wait_list) { for (MultiWaitHolderBase &holder_base : m_multi_wait_list) {
if (auto handle = holder_base.GetHandle(); handle != os::InvalidNativeHandle) { os::NativeHandle handle = os::InvalidNativeHandle;
if (holder_base.GetNativeHandle(std::addressof(handle))) {
AMS_ABORT_UNLESS(count < num); AMS_ABORT_UNLESS(count < num);
out_handles[count] = handle; out_handles[count] = handle;
out_objects[count] = std::addressof(holder_base); out_objects[count] = std::addressof(holder_base);
count++;
++count;
} }
} }
return count; return count;
} }
MultiWaitHolderBase *MultiWaitImpl::LinkHoldersToObjectList() { MultiWaitHolderBase *MultiWaitImpl::AddToEachObjectListAndCheckObjectState() {
/* Add each holder to the current object list, checking for the first signaled object. */
MultiWaitHolderBase *signaled_holder = nullptr; MultiWaitHolderBase *signaled_holder = nullptr;
for (MultiWaitHolderBase &holder_base : m_multi_wait_list) { for (MultiWaitHolderBase &holder_base : m_multi_wait_list) {
TriBool is_signaled = holder_base.LinkToObjectList(); if (const TriBool is_signaled = holder_base.AddToObjectList(); signaled_holder == nullptr && is_signaled == TriBool::True) {
if (signaled_holder == nullptr && is_signaled == TriBool::True) {
signaled_holder = std::addressof(holder_base); signaled_holder = std::addressof(holder_base);
} }
} }
@ -170,36 +215,43 @@ namespace ams::os::impl {
return signaled_holder; return signaled_holder;
} }
void MultiWaitImpl::UnlinkHoldersFromObjectList() { void MultiWaitImpl::RemoveFromEachObjectList() {
/* Remove each holder from the current object list. */
for (MultiWaitHolderBase &holder_base : m_multi_wait_list) { for (MultiWaitHolderBase &holder_base : m_multi_wait_list) {
holder_base.UnlinkFromObjectList(); holder_base.RemoveFromObjectList();
} }
} }
MultiWaitHolderBase *MultiWaitImpl::RecalculateNextTimeout(TimeSpan *out_min_timeout, TimeSpan end_time) { MultiWaitHolderBase *MultiWaitImpl::RecalcMultiWaitTimeout(TimeSpan *out_min_timeout, TimeSpan end_time) {
/* Find the holder with the minimum end time. */
MultiWaitHolderBase *min_timeout_holder = nullptr; MultiWaitHolderBase *min_timeout_holder = nullptr;
TimeSpan min_time = end_time; TimeSpan min_time = end_time;
for (MultiWaitHolderBase &holder_base : m_multi_wait_list) { for (MultiWaitHolderBase &holder_base : m_multi_wait_list) {
if (const TimeSpan cur_time = holder_base.GetAbsoluteWakeupTime(); cur_time < min_time) { if (const TimeSpan cur_time = holder_base.GetAbsoluteTimeToWakeup(); cur_time < min_time) {
min_timeout_holder = std::addressof(holder_base); min_timeout_holder = std::addressof(holder_base);
min_time = cur_time; min_time = cur_time;
} }
} }
/* If the minimum time is under the current time, we can't wait; otherwise, get the time to the minimum end time. */
if (min_time < m_current_time) { if (min_time < m_current_time) {
*out_min_timeout = 0; *out_min_timeout = 0;
} else { } else {
*out_min_timeout = min_time - m_current_time; *out_min_timeout = min_time - m_current_time;
} }
return min_timeout_holder; return min_timeout_holder;
} }
void MultiWaitImpl::SignalAndWakeupThread(MultiWaitHolderBase *holder_base) { void MultiWaitImpl::NotifyAndWakeupThread(MultiWaitHolderBase *holder_base) {
std::scoped_lock lk(m_cs_wait); std::scoped_lock lk(m_cs_wait);
/* If we don't have a signaled holder, set our signaled holder. */
if (m_signaled_holder == nullptr) { if (m_signaled_holder == nullptr) {
m_signaled_holder = holder_base; m_signaled_holder = holder_base;
/* Cancel any ongoing waits. */
m_target_impl.CancelWait(); m_target_impl.CancelWait();
} }
} }

View file

@ -44,24 +44,20 @@ namespace ams::os::impl {
InternalCriticalSection m_cs_wait; InternalCriticalSection m_cs_wait;
MultiWaitTargetImpl m_target_impl; MultiWaitTargetImpl m_target_impl;
private: private:
Result WaitAnyImpl(MultiWaitHolderBase **out, bool infinite, TimeSpan timeout, bool reply, NativeHandle reply_target); template<bool AllowReply>
Result WaitAnyHandleImpl(MultiWaitHolderBase **out, bool infinite, TimeSpan timeout, bool reply, NativeHandle reply_target); Result WaitAnyImpl(MultiWaitHolderBase **out, bool infinite, TimeSpan timeout, NativeHandle reply_target);
s32 BuildHandleArray(NativeHandle out_handles[], MultiWaitHolderBase *out_objects[], s32 num);
MultiWaitHolderBase *LinkHoldersToObjectList(); template<bool AllowReply>
void UnlinkHoldersFromObjectList(); Result InternalWaitAnyImpl(MultiWaitHolderBase **out, bool infinite, TimeSpan timeout, NativeHandle reply_target);
MultiWaitHolderBase *RecalculateNextTimeout(TimeSpan *out_min_timeout, TimeSpan end_time); s32 ConstructObjectsArray(NativeHandle out_handles[], MultiWaitHolderBase *out_objects[], s32 num);
MultiWaitHolderBase *WaitAnyImpl(bool infinite, TimeSpan timeout) { MultiWaitHolderBase *AddToEachObjectListAndCheckObjectState();
MultiWaitHolderBase *holder = nullptr; void RemoveFromEachObjectList();
const Result wait_result = this->WaitAnyImpl(std::addressof(holder), infinite, timeout, false, os::InvalidNativeHandle); MultiWaitHolderBase *RecalcMultiWaitTimeout(TimeSpan *out_min_timeout, TimeSpan end_time);
R_ASSERT(wait_result);
AMS_UNUSED(wait_result);
return holder; MultiWaitHolderBase *WaitAnyImpl(bool infinite, TimeSpan timeout);
}
public: public:
/* Wait. */ /* Wait. */
MultiWaitHolderBase *WaitAny() { MultiWaitHolderBase *WaitAny() {
@ -76,44 +72,47 @@ namespace ams::os::impl {
return this->WaitAnyImpl(false, ts); return this->WaitAnyImpl(false, ts);
} }
Result ReplyAndReceive(MultiWaitHolderBase **out, NativeHandle reply_target) { Result ReplyAndReceive(MultiWaitHolderBase **out, NativeHandle reply_target);
R_RETURN(this->WaitAnyImpl(out, true, TimeSpan::FromNanoSeconds(std::numeric_limits<s64>::max()), true, reply_target));
}
/* List management. */ /* List management. */
bool IsEmpty() const { bool IsListEmpty() const {
return m_multi_wait_list.empty(); return m_multi_wait_list.empty();
} }
void LinkMultiWaitHolder(MultiWaitHolderBase &holder_base) { bool IsListNotEmpty() const {
return !m_multi_wait_list.empty();
}
void PushBackToList(MultiWaitHolderBase &holder_base) {
m_multi_wait_list.push_back(holder_base); m_multi_wait_list.push_back(holder_base);
} }
void UnlinkMultiWaitHolder(MultiWaitHolderBase &holder_base) { void EraseFromList(MultiWaitHolderBase &holder_base) {
m_multi_wait_list.erase(m_multi_wait_list.iterator_to(holder_base)); m_multi_wait_list.erase(m_multi_wait_list.iterator_to(holder_base));
} }
void UnlinkAll() { void EraseAllFromList() {
while (!this->IsEmpty()) { while (!m_multi_wait_list.empty()) {
m_multi_wait_list.front().SetMultiWait(nullptr); m_multi_wait_list.front().SetMultiWait(nullptr);
m_multi_wait_list.pop_front(); m_multi_wait_list.pop_front();
} }
} }
void MoveAllFrom(MultiWaitImpl &other) { void MoveAllFromOther(MultiWaitImpl &other) {
/* Set ourselves as multi wait for all of the other's holders. */ /* Set ourselves as multi wait for all of the other's holders. */
for (auto &w : other.m_multi_wait_list) { for (auto &w : other.m_multi_wait_list) {
w.SetMultiWait(this); w.SetMultiWait(this);
} }
m_multi_wait_list.splice(m_multi_wait_list.end(), other.m_multi_wait_list); m_multi_wait_list.splice(m_multi_wait_list.end(), other.m_multi_wait_list);
} }
/* Other. */ /* Other. */
TimeSpan GetCurrentTime() const { TimeSpan GetCurrTime() const {
return m_current_time; return m_current_time;
} }
void SignalAndWakeupThread(MultiWaitHolderBase *holder_base); void NotifyAndWakeupThread(MultiWaitHolderBase *holder_base);
}; };
} }

View file

@ -25,15 +25,15 @@ namespace ams::os::impl {
private: private:
ListType m_object_list; ListType m_object_list;
public: public:
void SignalAllThreads() { void WakeupAllMultiWaitThreadsUnsafe() {
for (MultiWaitHolderBase &holder_base : m_object_list) { for (MultiWaitHolderBase &holder_base : m_object_list) {
holder_base.GetMultiWait()->SignalAndWakeupThread(std::addressof(holder_base)); holder_base.GetMultiWait()->NotifyAndWakeupThread(std::addressof(holder_base));
} }
} }
void BroadcastAllThreads() { void BroadcastToUpdateObjectStateUnsafe() {
for (MultiWaitHolderBase &holder_base : m_object_list) { for (MultiWaitHolderBase &holder_base : m_object_list) {
holder_base.GetMultiWait()->SignalAndWakeupThread(nullptr); holder_base.GetMultiWait()->NotifyAndWakeupThread(nullptr);
} }
} }
@ -41,11 +41,11 @@ namespace ams::os::impl {
return m_object_list.empty(); return m_object_list.empty();
} }
void LinkMultiWaitHolder(MultiWaitHolderBase &holder_base) { void PushBackToList(MultiWaitHolderBase &holder_base) {
m_object_list.push_back(holder_base); m_object_list.push_back(holder_base);
} }
void UnlinkMultiWaitHolder(MultiWaitHolderBase &holder_base) { void EraseFromList(MultiWaitHolderBase &holder_base) {
m_object_list.erase(m_object_list.iterator_to(holder_base)); m_object_list.erase(m_object_list.iterator_to(holder_base));
} }
}; };

View file

@ -111,7 +111,7 @@ namespace ams::os::impl {
thread->state = ThreadType::State_Terminated; thread->state = ThreadType::State_Terminated;
GetReference(thread->cv_thread).Broadcast(); GetReference(thread->cv_thread).Broadcast();
GetReference(thread->waitlist).SignalAllThreads(); GetReference(thread->waitlist).WakeupAllMultiWaitThreadsUnsafe();
} }
void ThreadManager::CleanupThread() { void ThreadManager::CleanupThread() {

View file

@ -34,7 +34,7 @@ namespace ams::os::impl {
event->timer_state = TimerEventType::TimerState_Stop; event->timer_state = TimerEventType::TimerState_Stop;
} }
bool UpdateSignalStateAndRecalculateNextTimeToWakeupUnsafe(TimerEventType *event, TimeSpan cur_time) { bool UpdateSignalStateAndRecalcNextTimeToWakeupUnsafe(TimerEventType *event, TimeSpan cur_time) {
TimeSpan next_time = GetReference(event->next_time_to_wakeup); TimeSpan next_time = GetReference(event->next_time_to_wakeup);
switch (event->timer_state) { switch (event->timer_state) {

View file

@ -24,7 +24,7 @@ namespace ams::os {
TimeSpan SaturatedAdd(TimeSpan t1, TimeSpan t2); TimeSpan SaturatedAdd(TimeSpan t1, TimeSpan t2);
void StopTimerUnsafe(TimerEventType *event); void StopTimerUnsafe(TimerEventType *event);
bool UpdateSignalStateAndRecalculateNextTimeToWakeupUnsafe(TimerEventType *event, TimeSpan cur_time); bool UpdateSignalStateAndRecalcNextTimeToWakeupUnsafe(TimerEventType *event, TimeSpan cur_time);
} }

View file

@ -89,7 +89,7 @@ namespace ams::os {
} }
/* Wake up whatever manager, if any. */ /* Wake up whatever manager, if any. */
GetReference(event->multi_wait_object_list_storage).SignalAllThreads(); GetReference(event->multi_wait_object_list_storage).WakeupAllMultiWaitThreadsUnsafe();
} }
void WaitEvent(EventType *event) { void WaitEvent(EventType *event) {

View file

@ -84,7 +84,7 @@ namespace ams::os {
/* Send, signal. */ /* Send, signal. */
MessageQueueHelper::EnqueueUnsafe(mq, data); MessageQueueHelper::EnqueueUnsafe(mq, data);
GetReference(mq->cv_not_empty).Broadcast(); GetReference(mq->cv_not_empty).Broadcast();
GetReference(mq->waitlist_not_empty).SignalAllThreads(); GetReference(mq->waitlist_not_empty).WakeupAllMultiWaitThreadsUnsafe();
} }
} }
@ -102,7 +102,7 @@ namespace ams::os {
/* Send, signal. */ /* Send, signal. */
MessageQueueHelper::EnqueueUnsafe(mq, data); MessageQueueHelper::EnqueueUnsafe(mq, data);
GetReference(mq->cv_not_empty).Broadcast(); GetReference(mq->cv_not_empty).Broadcast();
GetReference(mq->waitlist_not_empty).SignalAllThreads(); GetReference(mq->waitlist_not_empty).WakeupAllMultiWaitThreadsUnsafe();
} }
return true; return true;
@ -127,7 +127,7 @@ namespace ams::os {
/* Send, signal. */ /* Send, signal. */
MessageQueueHelper::EnqueueUnsafe(mq, data); MessageQueueHelper::EnqueueUnsafe(mq, data);
GetReference(mq->cv_not_empty).Broadcast(); GetReference(mq->cv_not_empty).Broadcast();
GetReference(mq->waitlist_not_empty).SignalAllThreads(); GetReference(mq->waitlist_not_empty).WakeupAllMultiWaitThreadsUnsafe();
} }
return true; return true;
@ -148,7 +148,7 @@ namespace ams::os {
/* Send, signal. */ /* Send, signal. */
MessageQueueHelper::JamUnsafe(mq, data); MessageQueueHelper::JamUnsafe(mq, data);
GetReference(mq->cv_not_empty).Broadcast(); GetReference(mq->cv_not_empty).Broadcast();
GetReference(mq->waitlist_not_empty).SignalAllThreads(); GetReference(mq->waitlist_not_empty).WakeupAllMultiWaitThreadsUnsafe();
} }
} }
@ -166,7 +166,7 @@ namespace ams::os {
/* Send, signal. */ /* Send, signal. */
MessageQueueHelper::JamUnsafe(mq, data); MessageQueueHelper::JamUnsafe(mq, data);
GetReference(mq->cv_not_empty).Broadcast(); GetReference(mq->cv_not_empty).Broadcast();
GetReference(mq->waitlist_not_empty).SignalAllThreads(); GetReference(mq->waitlist_not_empty).WakeupAllMultiWaitThreadsUnsafe();
} }
return true; return true;
@ -191,7 +191,7 @@ namespace ams::os {
/* Send, signal. */ /* Send, signal. */
MessageQueueHelper::JamUnsafe(mq, data); MessageQueueHelper::JamUnsafe(mq, data);
GetReference(mq->cv_not_empty).Broadcast(); GetReference(mq->cv_not_empty).Broadcast();
GetReference(mq->waitlist_not_empty).SignalAllThreads(); GetReference(mq->waitlist_not_empty).WakeupAllMultiWaitThreadsUnsafe();
} }
return true; return true;
@ -212,7 +212,7 @@ namespace ams::os {
/* Receive, signal. */ /* Receive, signal. */
*out = MessageQueueHelper::DequeueUnsafe(mq); *out = MessageQueueHelper::DequeueUnsafe(mq);
GetReference(mq->cv_not_full).Broadcast(); GetReference(mq->cv_not_full).Broadcast();
GetReference(mq->waitlist_not_full).SignalAllThreads(); GetReference(mq->waitlist_not_full).WakeupAllMultiWaitThreadsUnsafe();
} }
} }
@ -230,7 +230,7 @@ namespace ams::os {
/* Receive, signal. */ /* Receive, signal. */
*out = MessageQueueHelper::DequeueUnsafe(mq); *out = MessageQueueHelper::DequeueUnsafe(mq);
GetReference(mq->cv_not_full).Broadcast(); GetReference(mq->cv_not_full).Broadcast();
GetReference(mq->waitlist_not_full).SignalAllThreads(); GetReference(mq->waitlist_not_full).WakeupAllMultiWaitThreadsUnsafe();
} }
return true; return true;
@ -255,7 +255,7 @@ namespace ams::os {
/* Receive, signal. */ /* Receive, signal. */
*out = MessageQueueHelper::DequeueUnsafe(mq); *out = MessageQueueHelper::DequeueUnsafe(mq);
GetReference(mq->cv_not_full).Broadcast(); GetReference(mq->cv_not_full).Broadcast();
GetReference(mq->waitlist_not_full).SignalAllThreads(); GetReference(mq->waitlist_not_full).WakeupAllMultiWaitThreadsUnsafe();
} }
return true; return true;
@ -324,10 +324,10 @@ namespace ams::os {
switch (type) { switch (type) {
case MessageQueueWaitType::ForNotFull: case MessageQueueWaitType::ForNotFull:
util::ConstructAt(GetReference(multi_wait_holder->impl_storage).holder_of_mq_for_not_full_storage, mq); util::ConstructAt(GetReference(multi_wait_holder->impl_storage).holder_of_mq_not_full_storage, mq);
break; break;
case MessageQueueWaitType::ForNotEmpty: case MessageQueueWaitType::ForNotEmpty:
util::ConstructAt(GetReference(multi_wait_holder->impl_storage).holder_of_mq_for_not_empty_storage, mq); util::ConstructAt(GetReference(multi_wait_holder->impl_storage).holder_of_mq_not_empty_storage, mq);
break; break;
AMS_UNREACHABLE_DEFAULT_CASE(); AMS_UNREACHABLE_DEFAULT_CASE();
} }

View file

@ -44,7 +44,7 @@ namespace ams::os {
auto &impl = GetMultiWaitImpl(multi_wait); auto &impl = GetMultiWaitImpl(multi_wait);
AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized); AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized);
AMS_ASSERT(impl.IsEmpty()); AMS_ASSERT(impl.IsListEmpty());
AMS_UNUSED(impl); AMS_UNUSED(impl);
/* Mark not initialized. */ /* Mark not initialized. */
@ -58,7 +58,7 @@ namespace ams::os {
auto &impl = GetMultiWaitImpl(multi_wait); auto &impl = GetMultiWaitImpl(multi_wait);
AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized); AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized);
AMS_ASSERT(!impl.IsEmpty()); AMS_ASSERT(impl.IsListNotEmpty());
auto *holder = CastToMultiWaitHolder(impl.WaitAny()); auto *holder = CastToMultiWaitHolder(impl.WaitAny());
AMS_ASSERT(holder != nullptr); AMS_ASSERT(holder != nullptr);
@ -69,7 +69,7 @@ namespace ams::os {
auto &impl = GetMultiWaitImpl(multi_wait); auto &impl = GetMultiWaitImpl(multi_wait);
AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized); AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized);
AMS_ASSERT(!impl.IsEmpty()); AMS_ASSERT(impl.IsListNotEmpty());
auto *holder = CastToMultiWaitHolder(impl.TryWaitAny()); auto *holder = CastToMultiWaitHolder(impl.TryWaitAny());
return holder; return holder;
@ -79,7 +79,7 @@ namespace ams::os {
auto &impl = GetMultiWaitImpl(multi_wait); auto &impl = GetMultiWaitImpl(multi_wait);
AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized); AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized);
AMS_ASSERT(!impl.IsEmpty()); AMS_ASSERT(impl.IsListNotEmpty());
AMS_ASSERT(timeout.GetNanoSeconds() >= 0); AMS_ASSERT(timeout.GetNanoSeconds() >= 0);
auto *holder = CastToMultiWaitHolder(impl.TimedWaitAny(timeout)); auto *holder = CastToMultiWaitHolder(impl.TimedWaitAny(timeout));
@ -89,7 +89,7 @@ namespace ams::os {
void FinalizeMultiWaitHolder(MultiWaitHolderType *holder) { void FinalizeMultiWaitHolder(MultiWaitHolderType *holder) {
auto *holder_base = reinterpret_cast<impl::MultiWaitHolderBase *>(GetPointer(holder->impl_storage)); auto *holder_base = reinterpret_cast<impl::MultiWaitHolderBase *>(GetPointer(holder->impl_storage));
AMS_ASSERT(!holder_base->IsLinked()); AMS_ASSERT(holder_base->IsNotLinked());
/* Destroy. */ /* Destroy. */
static_assert(std::is_trivially_destructible<impl::MultiWaitHolderBase>::value); static_assert(std::is_trivially_destructible<impl::MultiWaitHolderBase>::value);
@ -102,9 +102,9 @@ namespace ams::os {
auto *holder_base = reinterpret_cast<impl::MultiWaitHolderBase *>(GetPointer(holder->impl_storage)); auto *holder_base = reinterpret_cast<impl::MultiWaitHolderBase *>(GetPointer(holder->impl_storage));
AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized); AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized);
AMS_ASSERT(!holder_base->IsLinked()); AMS_ASSERT(holder_base->IsNotLinked());
impl.LinkMultiWaitHolder(*holder_base); impl.PushBackToList(*holder_base);
holder_base->SetMultiWait(std::addressof(impl)); holder_base->SetMultiWait(std::addressof(impl));
} }
@ -114,7 +114,7 @@ namespace ams::os {
/* Don't allow unlinking of an unlinked holder. */ /* Don't allow unlinking of an unlinked holder. */
AMS_ABORT_UNLESS(holder_base->IsLinked()); AMS_ABORT_UNLESS(holder_base->IsLinked());
holder_base->GetMultiWait()->UnlinkMultiWaitHolder(*holder_base); holder_base->GetMultiWait()->EraseFromList(*holder_base);
holder_base->SetMultiWait(nullptr); holder_base->SetMultiWait(nullptr);
} }
@ -123,7 +123,7 @@ namespace ams::os {
AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized); AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized);
return impl.UnlinkAll(); return impl.EraseAllFromList();
} }
void MoveAllMultiWaitHolder(MultiWaitType *_dst, MultiWaitType *_src) { void MoveAllMultiWaitHolder(MultiWaitType *_dst, MultiWaitType *_src) {
@ -133,7 +133,7 @@ namespace ams::os {
AMS_ASSERT(_dst->state == MultiWaitType::State_Initialized); AMS_ASSERT(_dst->state == MultiWaitType::State_Initialized);
AMS_ASSERT(_src->state == MultiWaitType::State_Initialized); AMS_ASSERT(_src->state == MultiWaitType::State_Initialized);
return dst.MoveAllFrom(src); return dst.MoveAllFromOther(src);
} }
void SetMultiWaitHolderUserData(MultiWaitHolderType *holder, uintptr_t user_data) { void SetMultiWaitHolderUserData(MultiWaitHolderType *holder, uintptr_t user_data) {
@ -147,7 +147,7 @@ namespace ams::os {
void InitializeMultiWaitHolder(MultiWaitHolderType *holder, NativeHandle handle) { void InitializeMultiWaitHolder(MultiWaitHolderType *holder, NativeHandle handle) {
AMS_ASSERT(handle != os::InvalidNativeHandle); AMS_ASSERT(handle != os::InvalidNativeHandle);
util::ConstructAt(GetReference(holder->impl_storage).holder_of_handle_storage, handle); util::ConstructAt(GetReference(holder->impl_storage).holder_of_native_handle_storage, handle);
holder->user_data = 0; holder->user_data = 0;
} }

View file

@ -36,7 +36,7 @@ namespace ams::os {
auto &impl = GetMultiWaitImpl(multi_wait); auto &impl = GetMultiWaitImpl(multi_wait);
AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized); AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized);
AMS_ASSERT(!impl.IsEmpty()); AMS_ASSERT(impl.IsListNotEmpty());
impl::MultiWaitHolderBase *holder_base; impl::MultiWaitHolderBase *holder_base;
ON_SCOPE_EXIT { *out = CastToMultiWaitHolder(holder_base); }; ON_SCOPE_EXIT { *out = CastToMultiWaitHolder(holder_base); };

View file

@ -117,7 +117,7 @@ namespace ams::os {
++sema->count; ++sema->count;
GetReference(sema->cv_not_zero).Signal(); GetReference(sema->cv_not_zero).Signal();
GetReference(sema->waitlist).SignalAllThreads(); GetReference(sema->waitlist).WakeupAllMultiWaitThreadsUnsafe();
} }
} }
@ -132,7 +132,7 @@ namespace ams::os {
sema->count += count; sema->count += count;
GetReference(sema->cv_not_zero).Broadcast(); GetReference(sema->cv_not_zero).Broadcast();
GetReference(sema->waitlist).SignalAllThreads(); GetReference(sema->waitlist).WakeupAllMultiWaitThreadsUnsafe();
} }
} }

View file

@ -49,7 +49,7 @@ namespace ams::os {
} }
/* Wake up whatever manager, if any. */ /* Wake up whatever manager, if any. */
GetReference(event->multi_wait_object_list_storage).SignalAllThreads(); GetReference(event->multi_wait_object_list_storage).WakeupAllMultiWaitThreadsUnsafe();
} }
} }
@ -110,7 +110,7 @@ namespace ams::os {
GetReference(event->cv_signaled).Broadcast(); GetReference(event->cv_signaled).Broadcast();
/* Wake up whatever manager, if any. */ /* Wake up whatever manager, if any. */
GetReference(event->multi_wait_object_list_storage).SignalAllThreads(); GetReference(event->multi_wait_object_list_storage).WakeupAllMultiWaitThreadsUnsafe();
} }
} }
@ -137,7 +137,7 @@ namespace ams::os {
GetReference(event->cv_signaled).Broadcast(); GetReference(event->cv_signaled).Broadcast();
/* Wake up whatever manager, if any. */ /* Wake up whatever manager, if any. */
GetReference(event->multi_wait_object_list_storage).SignalAllThreads(); GetReference(event->multi_wait_object_list_storage).WakeupAllMultiWaitThreadsUnsafe();
} }
} }
@ -154,7 +154,7 @@ namespace ams::os {
GetReference(event->cv_signaled).Broadcast(); GetReference(event->cv_signaled).Broadcast();
/* Wake up whatever manager, if any. */ /* Wake up whatever manager, if any. */
GetReference(event->multi_wait_object_list_storage).SignalAllThreads(); GetReference(event->multi_wait_object_list_storage).WakeupAllMultiWaitThreadsUnsafe();
} }
} }
@ -172,7 +172,7 @@ namespace ams::os {
/* Update. */ /* Update. */
auto cur_time = impl::GetCurrentTick().ToTimeSpan(); auto cur_time = impl::GetCurrentTick().ToTimeSpan();
if (impl::UpdateSignalStateAndRecalculateNextTimeToWakeupUnsafe(event, cur_time)) { if (impl::UpdateSignalStateAndRecalcNextTimeToWakeupUnsafe(event, cur_time)) {
SignalTimerEventImplUnsafe(event); SignalTimerEventImplUnsafe(event);
break; break;
} }
@ -201,7 +201,7 @@ namespace ams::os {
/* Update. */ /* Update. */
auto cur_time = impl::GetCurrentTick().ToTimeSpan(); auto cur_time = impl::GetCurrentTick().ToTimeSpan();
if (impl::UpdateSignalStateAndRecalculateNextTimeToWakeupUnsafe(event, cur_time)) { if (impl::UpdateSignalStateAndRecalcNextTimeToWakeupUnsafe(event, cur_time)) {
SignalTimerEventImplUnsafe(event); SignalTimerEventImplUnsafe(event);
} }
@ -228,7 +228,7 @@ namespace ams::os {
/* Update. */ /* Update. */
auto cur_time = impl::GetCurrentTick().ToTimeSpan(); auto cur_time = impl::GetCurrentTick().ToTimeSpan();
impl::UpdateSignalStateAndRecalculateNextTimeToWakeupUnsafe(event, cur_time); impl::UpdateSignalStateAndRecalcNextTimeToWakeupUnsafe(event, cur_time);
/* Signal. */ /* Signal. */
SignalTimerEventImplUnsafe(event); SignalTimerEventImplUnsafe(event);
@ -243,7 +243,7 @@ namespace ams::os {
/* Update. */ /* Update. */
auto cur_time = impl::GetCurrentTick().ToTimeSpan(); auto cur_time = impl::GetCurrentTick().ToTimeSpan();
if (impl::UpdateSignalStateAndRecalculateNextTimeToWakeupUnsafe(event, cur_time)) { if (impl::UpdateSignalStateAndRecalcNextTimeToWakeupUnsafe(event, cur_time)) {
SignalTimerEventImplUnsafe(event); SignalTimerEventImplUnsafe(event);
} }