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:
/* Gets whether the held object is currently signaled. */
virtual TriBool IsSignaled() const = 0;
/* 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. */
virtual void UnlinkFromObjectList() = 0;
/* Gets handle to output, returns os::InvalidNativeHandle on failure. */
virtual NativeHandle GetHandle() const = 0;
virtual void RemoveFromObjectList() = 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. */
virtual TimeSpan GetAbsoluteWakeupTime() const {
virtual TimeSpan GetAbsoluteTimeToWakeup() const {
return TimeSpan::FromNanoSeconds(std::numeric_limits<s64>::max());
}
/* Interface with multi wait. */
void SetMultiWait(MultiWaitImpl *m) {
ALWAYS_INLINE void SetMultiWait(MultiWaitImpl *m) {
m_multi_wait = m;
}
MultiWaitImpl *GetMultiWait() const {
ALWAYS_INLINE MultiWaitImpl *GetMultiWait() const {
return m_multi_wait;
}
bool IsLinked() const {
return m_multi_wait != nullptr;
}
ALWAYS_INLINE bool IsLinked() const { return m_multi_wait != nullptr; }
ALWAYS_INLINE bool IsNotLinked() const { return m_multi_wait == nullptr; }
};
class MultiWaitHolderOfUserObject : public MultiWaitHolderBase {
class MultiWaitHolderOfUserWaitObject : public MultiWaitHolderBase {
public:
/* All user objects have no handle to wait on. */
virtual NativeHandle GetHandle() const override final {
return os::InvalidNativeHandle;
virtual bool GetNativeHandle(os::NativeHandle *) const override final {
return false;
}
};
class MultiWaitHolderOfKernelObject : public MultiWaitHolderBase {
class MultiWaitHolderOfNativeWaitObject : public MultiWaitHolderBase {
public:
/* All kernel objects have native handles, and thus don't have object list semantics. */
virtual TriBool LinkToObjectList() override final {
/* All native objects have native handles, and thus don't have object list semantics. */
virtual TriBool AddToObjectList() override final {
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/>.
*/
#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_inter_process_event.hpp"
#include "os_multiple_wait_holder_of_interrupt_event.hpp"
@ -27,30 +27,30 @@ namespace ams::os::impl {
struct MultiWaitHolderImpl {
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<MultiWaitHolderOfInterProcessEvent> holder_of_inter_process_event_storage;
util::TypedStorage<MultiWaitHolderOfInterruptEvent> holder_of_interrupt_event_storage;
util::TypedStorage<MultiWaitHolderOfTimerEvent> holder_of_timer_event_storage;
util::TypedStorage<MultiWaitHolderOfThread> holder_of_thread_storage;
util::TypedStorage<MultiWaitHolderOfSemaphore> holder_of_semaphore_storage;
util::TypedStorage<MultiWaitHolderOfMessageQueueForNotFull> holder_of_mq_for_not_full_storage;
util::TypedStorage<MultiWaitHolderOfMessageQueueForNotEmpty> holder_of_mq_for_not_empty_storage;
util::TypedStorage<MultiWaitHolderOfMessageQueueNotFull> holder_of_mq_not_full_storage;
util::TypedStorage<MultiWaitHolderOfMessageQueueNotEmpty> holder_of_mq_not_empty_storage;
};
};
#define CHECK_HOLDER(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(MultiWaitHolderOfInterProcessEvent);
CHECK_HOLDER(MultiWaitHolderOfInterruptEvent);
CHECK_HOLDER(MultiWaitHolderOfTimerEvent);
CHECK_HOLDER(MultiWaitHolderOfThread);
CHECK_HOLDER(MultiWaitHolderOfSemaphore);
CHECK_HOLDER(MultiWaitHolderOfMessageQueueForNotFull);
CHECK_HOLDER(MultiWaitHolderOfMessageQueueForNotEmpty);
CHECK_HOLDER(MultiWaitHolderOfMessageQueueNotFull);
CHECK_HOLDER(MultiWaitHolderOfMessageQueueNotEmpty);
#undef CHECK_HOLDER

View file

@ -19,11 +19,11 @@
namespace ams::os::impl {
class MultiWaitHolderOfEvent : public MultiWaitHolderOfUserObject {
class MultiWaitHolderOfEvent : public MultiWaitHolderOfUserWaitObject {
private:
EventType *m_event;
private:
TriBool IsSignaledImpl() const {
ALWAYS_INLINE TriBool IsSignaledUnsafe() const {
return m_event->signaled ? TriBool::True : TriBool::False;
}
public:
@ -32,20 +32,20 @@ namespace ams::os::impl {
/* IsSignaled, Link, Unlink implemented. */
virtual TriBool IsSignaled() const override {
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));
GetReference(m_event->multi_wait_object_list_storage).LinkMultiWaitHolder(*this);
return this->IsSignaledImpl();
GetReference(m_event->multi_wait_object_list_storage).PushBackToList(*this);
return this->IsSignaledUnsafe();
}
virtual void UnlinkFromObjectList() override {
virtual void RemoveFromObjectList() override {
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 {
class MultiWaitHolderOfInterProcessEvent : public MultiWaitHolderOfKernelObject {
class MultiWaitHolderOfInterProcessEvent : public MultiWaitHolderOfNativeWaitObject {
private:
InterProcessEventType *m_event;
public:
@ -30,8 +30,9 @@ namespace ams::os::impl {
return TriBool::Undefined;
}
virtual NativeHandle GetHandle() const override {
return m_event->readable_handle;
virtual bool GetNativeHandle(os::NativeHandle *out) const override {
*out = m_event->readable_handle;
return true;
}
};

View file

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

View file

@ -18,7 +18,7 @@
namespace ams::os::impl {
class MultiWaitHolderOfInterruptEvent : public MultiWaitHolderOfKernelObject {
class MultiWaitHolderOfInterruptEvent : public MultiWaitHolderOfNativeWaitObject {
private:
InterruptEventType *m_event;
public:
@ -29,7 +29,7 @@ namespace ams::os::impl {
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 {
template<MessageQueueWaitType WaitType>
class MultiWaitHolderOfMessageQueue : public MultiWaitHolderOfUserObject {
static_assert(WaitType == MessageQueueWaitType::ForNotEmpty || WaitType == MessageQueueWaitType::ForNotFull);
class MultiWaitHolderOfMessageQueueNotEmpty : public MultiWaitHolderOfUserWaitObject {
private:
MessageQueueType *m_mq;
private:
constexpr inline TriBool IsSignaledImpl() const {
if constexpr (WaitType == MessageQueueWaitType::ForNotEmpty) {
/* 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);
}
ALWAYS_INLINE TriBool IsSignaledUnsafe() const {
return m_mq->count > 0 ? TriBool::True : TriBool::False;
}
public:
explicit MultiWaitHolderOfMessageQueue(MessageQueueType *mq) : m_mq(mq) { /* ... */ }
explicit MultiWaitHolderOfMessageQueueNotEmpty(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->IsSignaledImpl();
return this->IsSignaledUnsafe();
}
virtual TriBool LinkToObjectList() override {
virtual TriBool AddToObjectList() override {
std::scoped_lock lk(GetReference(m_mq->cs_queue));
this->GetObjectList().LinkMultiWaitHolder(*this);
return this->IsSignaledImpl();
GetReference(m_mq->waitlist_not_empty).PushBackToList(*this);
return this->IsSignaledUnsafe();
}
virtual void UnlinkFromObjectList() override {
virtual void RemoveFromObjectList() override {
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>;
using MultiWaitHolderOfMessageQueueForNotFull = MultiWaitHolderOfMessageQueue<MessageQueueWaitType::ForNotFull>;
class MultiWaitHolderOfMessageQueueNotFull : public MultiWaitHolderOfUserWaitObject {
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 {
class MultiWaitHolderOfHandle : public MultiWaitHolderOfKernelObject {
class MultiWaitHolderOfNativeHandle : public MultiWaitHolderOfNativeWaitObject {
private:
NativeHandle m_handle;
public:
explicit MultiWaitHolderOfHandle(NativeHandle h) : m_handle(h) { /* ... */ }
explicit MultiWaitHolderOfNativeHandle(NativeHandle h) : m_handle(h) { /* ... */ }
/* IsSignaled, GetHandle both implemented. */
virtual TriBool IsSignaled() const override {
return TriBool::Undefined;
}
virtual NativeHandle GetHandle() const override {
return m_handle;
virtual bool GetNativeHandle(os::NativeHandle *out) const override {
*out = m_handle;
return true;
}
};

View file

@ -19,7 +19,7 @@
namespace ams::os::impl {
class MultiWaitHolderOfSemaphore : public MultiWaitHolderOfUserObject {
class MultiWaitHolderOfSemaphore : public MultiWaitHolderOfUserWaitObject {
private:
SemaphoreType *m_semaphore;
private:
@ -35,17 +35,17 @@ namespace ams::os::impl {
return this->IsSignaledImpl();
}
virtual TriBool LinkToObjectList() override {
virtual TriBool AddToObjectList() override {
std::scoped_lock lk(GetReference(m_semaphore->cs_sema));
GetReference(m_semaphore->waitlist).LinkMultiWaitHolder(*this);
GetReference(m_semaphore->waitlist).PushBackToList(*this);
return this->IsSignaledImpl();
}
virtual void UnlinkFromObjectList() override {
virtual void RemoveFromObjectList() override {
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 {
class MultiWaitHolderOfThread : public MultiWaitHolderOfUserObject {
class MultiWaitHolderOfThread : public MultiWaitHolderOfUserWaitObject {
private:
ThreadType *m_thread;
private:
@ -34,17 +34,17 @@ namespace ams::os::impl {
return this->IsSignaledImpl();
}
virtual TriBool LinkToObjectList() override {
virtual TriBool AddToObjectList() override {
std::scoped_lock lk(GetReference(m_thread->cs_thread));
GetReference(m_thread->waitlist).LinkMultiWaitHolder(*this);
GetReference(m_thread->waitlist).PushBackToList(*this);
return this->IsSignaledImpl();
}
virtual void UnlinkFromObjectList() override {
virtual void RemoveFromObjectList() override {
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 {
class MultiWaitHolderOfTimerEvent : public MultiWaitHolderOfUserObject {
class MultiWaitHolderOfTimerEvent : public MultiWaitHolderOfUserWaitObject {
private:
TimerEventType *m_event;
private:
TriBool IsSignaledImpl() const {
TimeSpan cur_time = this->GetMultiWait()->GetCurrentTime();
UpdateSignalStateAndRecalculateNextTimeToWakeupUnsafe(m_event, cur_time);
TriBool IsSignaledUnsafe() const {
TimeSpan cur_time = this->GetMultiWait()->GetCurrTime();
os::impl::UpdateSignalStateAndRecalcNextTimeToWakeupUnsafe(m_event, cur_time);
return m_event->signaled ? TriBool::True : TriBool::False;
}
public:
@ -36,31 +38,30 @@ namespace ams::os::impl {
/* IsSignaled, Link, Unlink implemented. */
virtual TriBool IsSignaled() const override {
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));
GetReference(m_event->multi_wait_object_list_storage).LinkMultiWaitHolder(*this);
return this->IsSignaledImpl();
GetReference(m_event->multi_wait_object_list_storage).PushBackToList(*this);
return this->IsSignaledUnsafe();
}
virtual void UnlinkFromObjectList() override {
virtual void RemoveFromObjectList() override {
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. */
virtual TimeSpan GetAbsoluteWakeupTime() const override {
virtual TimeSpan GetAbsoluteTimeToWakeup() const override {
std::scoped_lock lk(GetReference(m_event->cs_timer_event));
if (m_event->timer_state == TimerEventType::TimerState_Stop) {
return TimeSpan::FromNanoSeconds(std::numeric_limits<s64>::max());
}
return GetReference(m_event->next_time_to_wakeup);
return m_event->timer_state != TimerEventType::TimerState_Stop ? GetReference(m_event->next_time_to_wakeup)
: TimeSpan::FromNanoSeconds(std::numeric_limits<s64>::max());
}
};

View file

@ -20,149 +20,194 @@
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. */
m_signaled_holder = nullptr;
m_target_impl.SetCurrentThreadHandleForCancelWait();
MultiWaitHolderBase *holder = this->LinkHoldersToObjectList();
/* When we're done, cleanup and set output. */
ON_SCOPE_EXIT {
/* Unlink holders from the current object list. */
this->UnlinkHoldersFromObjectList();
/* Clear cancel wait. */
m_target_impl.ClearCurrentThreadHandleForCancelWait();
/* Set output holder. */
*out = holder;
};
/* Add each holder to the object list, and try to find one that's signaled. */
MultiWaitHolderBase *signaled_holder = this->AddToEachObjectListAndCheckObjectState();
/* Check if we've been signaled. */
{
std::scoped_lock lk(m_cs_wait);
if (m_signaled_holder != nullptr) {
holder = m_signaled_holder;
signaled_holder = m_signaled_holder;
}
}
/* Process object array. */
if (holder != nullptr) {
R_SUCCEED_IF(!(reply && reply_target != os::InvalidNativeHandle));
ON_RESULT_FAILURE { holder = nullptr; };
s32 index;
R_RETURN(m_target_impl.TimedReplyAndReceive(std::addressof(index), nullptr, 0, 0, reply_target, TimeSpan::FromNanoSeconds(0)))
if (signaled_holder != nullptr) {
/* If we have a signaled holder and we're allowed to reply, try to do so. */
if constexpr (AllowReply) {
/* Try to reply to the reply target. */
if (reply_target != os::InvalidNativeHandle) {
s32 index;
R_TRY(m_target_impl.TimedReplyAndReceive(std::addressof(index), nullptr, 0, 0, reply_target, TimeSpan::FromNanoSeconds(0)));
}
}
} 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];
MultiWaitHolderBase *objects[MaximumHandleCount];
const s32 count = this->BuildHandleArray(object_handles, objects, MaximumHandleCount);
const TimeSpan end_time = infinite ? TimeSpan::FromNanoSeconds(std::numeric_limits<s64>::max()) : GetCurrentTick().ToTimeSpan() + timeout;
const s32 count = this->ConstructObjectsArray(object_handles, objects, MaximumHandleCount);
/* 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) {
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;
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();
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);
} 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 {
if (count == 0 && min_timeout == 0) {
index = WaitTimedOut;
/* We need to do our wait with a timeout. */
if constexpr (AllowReply) {
wait_result = m_target_impl.TimedReplyAndReceive(std::addressof(index), object_handles, MaximumHandleCount, count, reply_target, min_timeout);
} else {
wait_result = m_target_impl.TimedWaitAny(std::addressof(index), object_handles, MaximumHandleCount, count, min_timeout);
AMS_ABORT_UNLESS(index != WaitInvalid);
if (count != 0 || min_timeout != 0) {
wait_result = m_target_impl.TimedWaitAny(std::addressof(index), object_handles, MaximumHandleCount, count, min_timeout);
} else {
index = WaitTimedOut;
}
}
}
if (index == WaitInvalid) {
*out = nullptr;
R_RETURN(wait_result);
}
/* Process the result of our wait. */
switch (index) {
case WaitTimedOut:
if (min_timeout_object) {
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 {
case WaitInvalid:
/* If an invalid wait was performed, just return no signaled holder. */
{
*out = nullptr;
R_RETURN(wait_result);
}
break;
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);
if (m_signaled_holder) {
*out = m_signaled_holder;
R_RETURN(wait_result);
}
}
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. */
{
if constexpr (MaximumHandleCount > 0) {
AMS_ASSERT(0 <= index && index < static_cast<s32>(MaximumHandleCount));
/* Sanity check that the returned index is within the range of our objects array. */
AMS_ASSERT(0 <= index && index < count);
std::scoped_lock lk(m_cs_wait);
m_signaled_holder = objects[index];
*out = objects[index];
R_RETURN(wait_result);
} else {
AMS_ABORT_UNLESS(MaximumHandleCount > 0);
}
std::scoped_lock lk(m_cs_wait);
/* Set our signaled holder (and the output) as the newly signaled object. */
m_signaled_holder = objects[index];
*out = objects[index];
R_RETURN(wait_result);
}
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;
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);
out_handles[count] = handle;
out_objects[count] = std::addressof(holder_base);
count++;
++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;
for (MultiWaitHolderBase &holder_base : m_multi_wait_list) {
TriBool is_signaled = holder_base.LinkToObjectList();
if (signaled_holder == nullptr && is_signaled == TriBool::True) {
if (const TriBool is_signaled = holder_base.AddToObjectList(); signaled_holder == nullptr && is_signaled == TriBool::True) {
signaled_holder = std::addressof(holder_base);
}
}
@ -170,36 +215,43 @@ namespace ams::os::impl {
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) {
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;
TimeSpan min_time = end_time;
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_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) {
*out_min_timeout = 0;
} else {
*out_min_timeout = min_time - m_current_time;
}
return min_timeout_holder;
}
void MultiWaitImpl::SignalAndWakeupThread(MultiWaitHolderBase *holder_base) {
void MultiWaitImpl::NotifyAndWakeupThread(MultiWaitHolderBase *holder_base) {
std::scoped_lock lk(m_cs_wait);
/* If we don't have a signaled holder, set our signaled holder. */
if (m_signaled_holder == nullptr) {
m_signaled_holder = holder_base;
/* Cancel any ongoing waits. */
m_target_impl.CancelWait();
}
}

View file

@ -44,24 +44,20 @@ namespace ams::os::impl {
InternalCriticalSection m_cs_wait;
MultiWaitTargetImpl m_target_impl;
private:
Result WaitAnyImpl(MultiWaitHolderBase **out, bool infinite, TimeSpan timeout, bool reply, NativeHandle reply_target);
Result WaitAnyHandleImpl(MultiWaitHolderBase **out, bool infinite, TimeSpan timeout, bool reply, NativeHandle reply_target);
s32 BuildHandleArray(NativeHandle out_handles[], MultiWaitHolderBase *out_objects[], s32 num);
template<bool AllowReply>
Result WaitAnyImpl(MultiWaitHolderBase **out, bool infinite, TimeSpan timeout, NativeHandle reply_target);
MultiWaitHolderBase *LinkHoldersToObjectList();
void UnlinkHoldersFromObjectList();
template<bool AllowReply>
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 *holder = nullptr;
MultiWaitHolderBase *AddToEachObjectListAndCheckObjectState();
void RemoveFromEachObjectList();
const Result wait_result = this->WaitAnyImpl(std::addressof(holder), infinite, timeout, false, os::InvalidNativeHandle);
R_ASSERT(wait_result);
AMS_UNUSED(wait_result);
MultiWaitHolderBase *RecalcMultiWaitTimeout(TimeSpan *out_min_timeout, TimeSpan end_time);
return holder;
}
MultiWaitHolderBase *WaitAnyImpl(bool infinite, TimeSpan timeout);
public:
/* Wait. */
MultiWaitHolderBase *WaitAny() {
@ -76,44 +72,47 @@ namespace ams::os::impl {
return this->WaitAnyImpl(false, ts);
}
Result ReplyAndReceive(MultiWaitHolderBase **out, NativeHandle reply_target) {
R_RETURN(this->WaitAnyImpl(out, true, TimeSpan::FromNanoSeconds(std::numeric_limits<s64>::max()), true, reply_target));
}
Result ReplyAndReceive(MultiWaitHolderBase **out, NativeHandle reply_target);
/* List management. */
bool IsEmpty() const {
bool IsListEmpty() const {
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);
}
void UnlinkMultiWaitHolder(MultiWaitHolderBase &holder_base) {
void EraseFromList(MultiWaitHolderBase &holder_base) {
m_multi_wait_list.erase(m_multi_wait_list.iterator_to(holder_base));
}
void UnlinkAll() {
while (!this->IsEmpty()) {
void EraseAllFromList() {
while (!m_multi_wait_list.empty()) {
m_multi_wait_list.front().SetMultiWait(nullptr);
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. */
for (auto &w : other.m_multi_wait_list) {
w.SetMultiWait(this);
}
m_multi_wait_list.splice(m_multi_wait_list.end(), other.m_multi_wait_list);
}
/* Other. */
TimeSpan GetCurrentTime() const {
TimeSpan GetCurrTime() const {
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:
ListType m_object_list;
public:
void SignalAllThreads() {
void WakeupAllMultiWaitThreadsUnsafe() {
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) {
holder_base.GetMultiWait()->SignalAndWakeupThread(nullptr);
holder_base.GetMultiWait()->NotifyAndWakeupThread(nullptr);
}
}
@ -41,11 +41,11 @@ namespace ams::os::impl {
return m_object_list.empty();
}
void LinkMultiWaitHolder(MultiWaitHolderBase &holder_base) {
void PushBackToList(MultiWaitHolderBase &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));
}
};

View file

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

View file

@ -34,7 +34,7 @@ namespace ams::os::impl {
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);
switch (event->timer_state) {

View file

@ -24,7 +24,7 @@ namespace ams::os {
TimeSpan SaturatedAdd(TimeSpan t1, TimeSpan t2);
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. */
GetReference(event->multi_wait_object_list_storage).SignalAllThreads();
GetReference(event->multi_wait_object_list_storage).WakeupAllMultiWaitThreadsUnsafe();
}
void WaitEvent(EventType *event) {

View file

@ -84,7 +84,7 @@ namespace ams::os {
/* Send, signal. */
MessageQueueHelper::EnqueueUnsafe(mq, data);
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. */
MessageQueueHelper::EnqueueUnsafe(mq, data);
GetReference(mq->cv_not_empty).Broadcast();
GetReference(mq->waitlist_not_empty).SignalAllThreads();
GetReference(mq->waitlist_not_empty).WakeupAllMultiWaitThreadsUnsafe();
}
return true;
@ -127,7 +127,7 @@ namespace ams::os {
/* Send, signal. */
MessageQueueHelper::EnqueueUnsafe(mq, data);
GetReference(mq->cv_not_empty).Broadcast();
GetReference(mq->waitlist_not_empty).SignalAllThreads();
GetReference(mq->waitlist_not_empty).WakeupAllMultiWaitThreadsUnsafe();
}
return true;
@ -148,7 +148,7 @@ namespace ams::os {
/* Send, signal. */
MessageQueueHelper::JamUnsafe(mq, data);
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. */
MessageQueueHelper::JamUnsafe(mq, data);
GetReference(mq->cv_not_empty).Broadcast();
GetReference(mq->waitlist_not_empty).SignalAllThreads();
GetReference(mq->waitlist_not_empty).WakeupAllMultiWaitThreadsUnsafe();
}
return true;
@ -191,7 +191,7 @@ namespace ams::os {
/* Send, signal. */
MessageQueueHelper::JamUnsafe(mq, data);
GetReference(mq->cv_not_empty).Broadcast();
GetReference(mq->waitlist_not_empty).SignalAllThreads();
GetReference(mq->waitlist_not_empty).WakeupAllMultiWaitThreadsUnsafe();
}
return true;
@ -212,7 +212,7 @@ namespace ams::os {
/* Receive, signal. */
*out = MessageQueueHelper::DequeueUnsafe(mq);
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. */
*out = MessageQueueHelper::DequeueUnsafe(mq);
GetReference(mq->cv_not_full).Broadcast();
GetReference(mq->waitlist_not_full).SignalAllThreads();
GetReference(mq->waitlist_not_full).WakeupAllMultiWaitThreadsUnsafe();
}
return true;
@ -255,7 +255,7 @@ namespace ams::os {
/* Receive, signal. */
*out = MessageQueueHelper::DequeueUnsafe(mq);
GetReference(mq->cv_not_full).Broadcast();
GetReference(mq->waitlist_not_full).SignalAllThreads();
GetReference(mq->waitlist_not_full).WakeupAllMultiWaitThreadsUnsafe();
}
return true;
@ -324,10 +324,10 @@ namespace ams::os {
switch (type) {
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;
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;
AMS_UNREACHABLE_DEFAULT_CASE();
}

View file

@ -44,7 +44,7 @@ namespace ams::os {
auto &impl = GetMultiWaitImpl(multi_wait);
AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized);
AMS_ASSERT(impl.IsEmpty());
AMS_ASSERT(impl.IsListEmpty());
AMS_UNUSED(impl);
/* Mark not initialized. */
@ -58,7 +58,7 @@ namespace ams::os {
auto &impl = GetMultiWaitImpl(multi_wait);
AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized);
AMS_ASSERT(!impl.IsEmpty());
AMS_ASSERT(impl.IsListNotEmpty());
auto *holder = CastToMultiWaitHolder(impl.WaitAny());
AMS_ASSERT(holder != nullptr);
@ -69,7 +69,7 @@ namespace ams::os {
auto &impl = GetMultiWaitImpl(multi_wait);
AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized);
AMS_ASSERT(!impl.IsEmpty());
AMS_ASSERT(impl.IsListNotEmpty());
auto *holder = CastToMultiWaitHolder(impl.TryWaitAny());
return holder;
@ -79,7 +79,7 @@ namespace ams::os {
auto &impl = GetMultiWaitImpl(multi_wait);
AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized);
AMS_ASSERT(!impl.IsEmpty());
AMS_ASSERT(impl.IsListNotEmpty());
AMS_ASSERT(timeout.GetNanoSeconds() >= 0);
auto *holder = CastToMultiWaitHolder(impl.TimedWaitAny(timeout));
@ -89,7 +89,7 @@ namespace ams::os {
void FinalizeMultiWaitHolder(MultiWaitHolderType *holder) {
auto *holder_base = reinterpret_cast<impl::MultiWaitHolderBase *>(GetPointer(holder->impl_storage));
AMS_ASSERT(!holder_base->IsLinked());
AMS_ASSERT(holder_base->IsNotLinked());
/* Destroy. */
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));
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));
}
@ -114,7 +114,7 @@ namespace ams::os {
/* Don't allow unlinking of an unlinked holder. */
AMS_ABORT_UNLESS(holder_base->IsLinked());
holder_base->GetMultiWait()->UnlinkMultiWaitHolder(*holder_base);
holder_base->GetMultiWait()->EraseFromList(*holder_base);
holder_base->SetMultiWait(nullptr);
}
@ -123,7 +123,7 @@ namespace ams::os {
AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized);
return impl.UnlinkAll();
return impl.EraseAllFromList();
}
void MoveAllMultiWaitHolder(MultiWaitType *_dst, MultiWaitType *_src) {
@ -133,7 +133,7 @@ namespace ams::os {
AMS_ASSERT(_dst->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) {
@ -147,7 +147,7 @@ namespace ams::os {
void InitializeMultiWaitHolder(MultiWaitHolderType *holder, NativeHandle handle) {
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;
}

View file

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

View file

@ -117,7 +117,7 @@ namespace ams::os {
++sema->count;
GetReference(sema->cv_not_zero).Signal();
GetReference(sema->waitlist).SignalAllThreads();
GetReference(sema->waitlist).WakeupAllMultiWaitThreadsUnsafe();
}
}
@ -132,7 +132,7 @@ namespace ams::os {
sema->count += count;
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. */
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();
/* 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();
/* 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();
/* 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. */
auto cur_time = impl::GetCurrentTick().ToTimeSpan();
if (impl::UpdateSignalStateAndRecalculateNextTimeToWakeupUnsafe(event, cur_time)) {
if (impl::UpdateSignalStateAndRecalcNextTimeToWakeupUnsafe(event, cur_time)) {
SignalTimerEventImplUnsafe(event);
break;
}
@ -201,7 +201,7 @@ namespace ams::os {
/* Update. */
auto cur_time = impl::GetCurrentTick().ToTimeSpan();
if (impl::UpdateSignalStateAndRecalculateNextTimeToWakeupUnsafe(event, cur_time)) {
if (impl::UpdateSignalStateAndRecalcNextTimeToWakeupUnsafe(event, cur_time)) {
SignalTimerEventImplUnsafe(event);
}
@ -228,7 +228,7 @@ namespace ams::os {
/* Update. */
auto cur_time = impl::GetCurrentTick().ToTimeSpan();
impl::UpdateSignalStateAndRecalculateNextTimeToWakeupUnsafe(event, cur_time);
impl::UpdateSignalStateAndRecalcNextTimeToWakeupUnsafe(event, cur_time);
/* Signal. */
SignalTimerEventImplUnsafe(event);
@ -243,7 +243,7 @@ namespace ams::os {
/* Update. */
auto cur_time = impl::GetCurrentTick().ToTimeSpan();
if (impl::UpdateSignalStateAndRecalculateNextTimeToWakeupUnsafe(event, cur_time)) {
if (impl::UpdateSignalStateAndRecalcNextTimeToWakeupUnsafe(event, cur_time)) {
SignalTimerEventImplUnsafe(event);
}