mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 12:21:18 +00:00
os: refactor multi wait apis to better match Nintendo's latest implementation
This commit is contained in:
parent
b45671fd35
commit
02b126c2be
23 changed files with 309 additions and 243 deletions
|
@ -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 {
|
||||
/* ... */
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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); };
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue