mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +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:
|
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 {
|
||||||
/* ... */
|
/* ... */
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
|
||||||
/* ForNotEmpty. */
|
|
||||||
return m_mq->count > 0 ? TriBool::True : TriBool::False;
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
|
||||||
R_RETURN(this->WaitAnyHandleImpl(std::addressof(holder), infinite, timeout, reply, reply_target));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
/* 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));
|
||||||
|
}
|
||||||
|
|
||||||
Result MultiWaitImpl::WaitAnyHandleImpl(MultiWaitHolderBase **out, bool infinite, TimeSpan timeout, bool reply, NativeHandle 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* Perform the wait using native apis. */
|
||||||
s32 index = WaitInvalid;
|
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);
|
|
||||||
}
|
|
||||||
} else if (infinite && min_timeout_object == nullptr) {
|
|
||||||
wait_result = m_target_impl.WaitAny(std::addressof(index), object_handles, MaximumHandleCount, count);
|
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 {
|
||||||
|
if (count != 0 || min_timeout != 0) {
|
||||||
wait_result = m_target_impl.TimedWaitAny(std::addressof(index), object_handles, MaximumHandleCount, count, min_timeout);
|
wait_result = m_target_impl.TimedWaitAny(std::addressof(index), object_handles, MaximumHandleCount, count, min_timeout);
|
||||||
AMS_ABORT_UNLESS(index != WaitInvalid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index == WaitInvalid) {
|
|
||||||
*out = nullptr;
|
|
||||||
R_RETURN(wait_result);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
} else {
|
||||||
|
index = WaitTimedOut;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process the result of our wait. */
|
||||||
|
switch (index) {
|
||||||
|
case WaitInvalid:
|
||||||
|
/* If an invalid wait was performed, just return no signaled holder. */
|
||||||
|
{
|
||||||
*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);
|
||||||
|
|
||||||
|
/* Set our signaled holder (and the output) as the newly signaled object. */
|
||||||
m_signaled_holder = objects[index];
|
m_signaled_holder = objects[index];
|
||||||
*out = objects[index];
|
*out = objects[index];
|
||||||
R_RETURN(wait_result);
|
R_RETURN(wait_result);
|
||||||
} else {
|
|
||||||
AMS_ABORT_UNLESS(MaximumHandleCount > 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We're going to be looping again; prevent ourselves from replying to the same object twice. */
|
||||||
|
if constexpr (AllowReply) {
|
||||||
reply_target = os::InvalidNativeHandle;
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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); };
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue