mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
os: implement 11.x SdkReplyAndReceive
This commit is contained in:
parent
b26ebc12e1
commit
8ac8abf295
12 changed files with 296 additions and 37 deletions
|
@ -19,6 +19,7 @@
|
||||||
#include <stratosphere/os/os_common_types.hpp>
|
#include <stratosphere/os/os_common_types.hpp>
|
||||||
#include <stratosphere/os/os_tick.hpp>
|
#include <stratosphere/os/os_tick.hpp>
|
||||||
#include <stratosphere/os/os_memory_common.hpp>
|
#include <stratosphere/os/os_memory_common.hpp>
|
||||||
|
#include <stratosphere/os/os_memory_fence.hpp>
|
||||||
#include <stratosphere/os/os_memory_permission.hpp>
|
#include <stratosphere/os/os_memory_permission.hpp>
|
||||||
#include <stratosphere/os/os_memory_heap_api.hpp>
|
#include <stratosphere/os/os_memory_heap_api.hpp>
|
||||||
#include <stratosphere/os/os_memory_virtual_address_api.hpp>
|
#include <stratosphere/os/os_memory_virtual_address_api.hpp>
|
||||||
|
@ -38,6 +39,7 @@
|
||||||
#include <stratosphere/os/os_timer_event.hpp>
|
#include <stratosphere/os/os_timer_event.hpp>
|
||||||
#include <stratosphere/os/os_thread_local_storage.hpp>
|
#include <stratosphere/os/os_thread_local_storage.hpp>
|
||||||
#include <stratosphere/os/os_sdk_thread_local_storage.hpp>
|
#include <stratosphere/os/os_sdk_thread_local_storage.hpp>
|
||||||
|
#include <stratosphere/os/os_sdk_reply_and_receive.hpp>
|
||||||
#include <stratosphere/os/os_thread.hpp>
|
#include <stratosphere/os/os_thread.hpp>
|
||||||
#include <stratosphere/os/os_message_queue.hpp>
|
#include <stratosphere/os/os_message_queue.hpp>
|
||||||
#include <stratosphere/os/os_waitable.hpp>
|
#include <stratosphere/os/os_waitable.hpp>
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
|
||||||
|
namespace ams::os::impl {
|
||||||
|
|
||||||
|
#if defined(ATMOSPHERE_ARCH_ARM64)
|
||||||
|
|
||||||
|
ALWAYS_INLINE void FenceMemoryStoreStore() { __asm__ __volatile__("dmb ishst" ::: "memory"); }
|
||||||
|
ALWAYS_INLINE void FenceMemoryStoreLoad() { __asm__ __volatile__("dmb ish" ::: "memory"); }
|
||||||
|
ALWAYS_INLINE void FenceMemoryStoreAny() { __asm__ __volatile__("dmb ish" ::: "memory"); }
|
||||||
|
|
||||||
|
ALWAYS_INLINE void FenceMemoryLoadStore() { __asm__ __volatile__("dmb ishld" ::: "memory"); }
|
||||||
|
ALWAYS_INLINE void FenceMemoryLoadLoad() { __asm__ __volatile__("dmb ishld" ::: "memory"); }
|
||||||
|
ALWAYS_INLINE void FenceMemoryLoadAny() { __asm__ __volatile__("dmb ishld" ::: "memory"); }
|
||||||
|
|
||||||
|
ALWAYS_INLINE void FenceMemoryAnyStore() { __asm__ __volatile__("dmb ish" ::: "memory"); }
|
||||||
|
ALWAYS_INLINE void FenceMemoryAnyLoad() { __asm__ __volatile__("dmb ish" ::: "memory"); }
|
||||||
|
ALWAYS_INLINE void FenceMemoryAnyAny() { __asm__ __volatile__("dmb ish" ::: "memory"); }
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#error "Unknown architecture for os::impl::FenceMemory* (Horizon)"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere/os/os_memory_fence_api.hpp>
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
|
||||||
|
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||||
|
#include <stratosphere/os/impl/os_memory_fence_api.os.horizon.hpp>
|
||||||
|
#else
|
||||||
|
#error "Unknown os for os::MemoryFence*"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace ams::os {
|
||||||
|
|
||||||
|
ALWAYS_INLINE void FenceMemoryStoreStore() { return impl::FenceMemoryStoreStore(); }
|
||||||
|
ALWAYS_INLINE void FenceMemoryStoreLoad() { return impl::FenceMemoryStoreLoad(); }
|
||||||
|
ALWAYS_INLINE void FenceMemoryStoreAny() { return impl::FenceMemoryStoreAny(); }
|
||||||
|
|
||||||
|
ALWAYS_INLINE void FenceMemoryLoadStore() { return impl::FenceMemoryLoadStore(); }
|
||||||
|
ALWAYS_INLINE void FenceMemoryLoadLoad() { return impl::FenceMemoryLoadLoad(); }
|
||||||
|
ALWAYS_INLINE void FenceMemoryLoadAny() { return impl::FenceMemoryLoadAny(); }
|
||||||
|
|
||||||
|
ALWAYS_INLINE void FenceMemoryAnyStore() { return impl::FenceMemoryLoadStore(); }
|
||||||
|
ALWAYS_INLINE void FenceMemoryAnyLoad() { return impl::FenceMemoryLoadLoad(); }
|
||||||
|
ALWAYS_INLINE void FenceMemoryAnyAny() { return impl::FenceMemoryLoadAny(); }
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
|
||||||
|
namespace ams::os {
|
||||||
|
|
||||||
|
struct WaitableHolderType;
|
||||||
|
struct WaitableManagerType;
|
||||||
|
|
||||||
|
Result SdkReplyAndReceive(os::WaitableHolderType **out, Handle reply_target, WaitableManagerType *manager);
|
||||||
|
|
||||||
|
}
|
|
@ -20,23 +20,32 @@
|
||||||
|
|
||||||
namespace ams::os::impl {
|
namespace ams::os::impl {
|
||||||
|
|
||||||
WaitableHolderBase *WaitableManagerImpl::WaitAnyImpl(bool infinite, TimeSpan timeout) {
|
Result WaitableManagerImpl::WaitAnyImpl(WaitableHolderBase **out, bool infinite, TimeSpan timeout, bool reply, Handle reply_target) {
|
||||||
/* Prepare for processing. */
|
/* Prepare for processing. */
|
||||||
this->signaled_holder = nullptr;
|
this->signaled_holder = nullptr;
|
||||||
this->target_impl.SetCurrentThreadHandleForCancelWait();
|
this->target_impl.SetCurrentThreadHandleForCancelWait();
|
||||||
WaitableHolderBase *result = this->LinkHoldersToObjectList();
|
WaitableHolderBase *holder = this->LinkHoldersToObjectList();
|
||||||
|
|
||||||
/* Check if we've been signaled. */
|
/* Check if we've been signaled. */
|
||||||
{
|
{
|
||||||
std::scoped_lock lk(this->cs_wait);
|
std::scoped_lock lk(this->cs_wait);
|
||||||
if (this->signaled_holder != nullptr) {
|
if (this->signaled_holder != nullptr) {
|
||||||
result = this->signaled_holder;
|
holder = this->signaled_holder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process object array. */
|
/* Process object array. */
|
||||||
if (result == nullptr) {
|
Result wait_result = ResultSuccess();
|
||||||
result = this->WaitAnyHandleImpl(infinite, timeout);
|
if (holder != nullptr) {
|
||||||
|
if (reply && reply_target != svc::InvalidHandle) {
|
||||||
|
s32 index;
|
||||||
|
wait_result = this->target_impl.TimedReplyAndReceive(std::addressof(index), nullptr, 0, 0, reply_target, TimeSpan::FromNanoSeconds(0));
|
||||||
|
if (R_FAILED(wait_result)) {
|
||||||
|
holder = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wait_result = this->WaitAnyHandleImpl(std::addressof(holder), infinite, timeout, reply, reply_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unlink holders from the current object list. */
|
/* Unlink holders from the current object list. */
|
||||||
|
@ -44,10 +53,13 @@ namespace ams::os::impl {
|
||||||
|
|
||||||
this->target_impl.ClearCurrentThreadHandleForCancelWait();
|
this->target_impl.ClearCurrentThreadHandleForCancelWait();
|
||||||
|
|
||||||
return result;
|
/* Set output holder. */
|
||||||
|
*out = holder;
|
||||||
|
|
||||||
|
return wait_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
WaitableHolderBase *WaitableManagerImpl::WaitAnyHandleImpl(bool infinite, TimeSpan timeout) {
|
Result WaitableManagerImpl::WaitAnyHandleImpl(WaitableHolderBase **out, bool infinite, TimeSpan timeout, bool reply, Handle reply_target) {
|
||||||
Handle object_handles[MaximumHandleCount];
|
Handle object_handles[MaximumHandleCount];
|
||||||
WaitableHolderBase *objects[MaximumHandleCount];
|
WaitableHolderBase *objects[MaximumHandleCount];
|
||||||
|
|
||||||
|
@ -60,18 +72,30 @@ namespace ams::os::impl {
|
||||||
TimeSpan min_timeout = 0;
|
TimeSpan min_timeout = 0;
|
||||||
WaitableHolderBase *min_timeout_object = this->RecalculateNextTimeout(&min_timeout, end_time);
|
WaitableHolderBase *min_timeout_object = this->RecalculateNextTimeout(&min_timeout, end_time);
|
||||||
|
|
||||||
s32 index;
|
s32 index = WaitInvalid;
|
||||||
|
Result wait_result = ResultSuccess();
|
||||||
|
if (reply) {
|
||||||
if (infinite && min_timeout_object == nullptr) {
|
if (infinite && min_timeout_object == nullptr) {
|
||||||
index = this->target_impl.WaitAny(object_handles, MaximumHandleCount, count);
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
} else if (infinite && min_timeout_object == nullptr) {
|
||||||
|
wait_result = this->target_impl.WaitAny(std::addressof(index), object_handles, MaximumHandleCount, count);
|
||||||
} else {
|
} else {
|
||||||
if (count == 0 && min_timeout == 0) {
|
if (count == 0 && min_timeout == 0) {
|
||||||
index = WaitTimedOut;
|
index = WaitTimedOut;
|
||||||
} else {
|
} else {
|
||||||
index = this->target_impl.TimedWaitAny(object_handles, MaximumHandleCount, count, min_timeout);
|
wait_result = this->target_impl.TimedWaitAny(std::addressof(index), object_handles, MaximumHandleCount, count, min_timeout);
|
||||||
AMS_ABORT_UNLESS(index != WaitInvalid);
|
AMS_ABORT_UNLESS(index != WaitInvalid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (index == WaitInvalid) {
|
||||||
|
*out = nullptr;
|
||||||
|
return wait_result;
|
||||||
|
}
|
||||||
|
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case WaitTimedOut:
|
case WaitTimedOut:
|
||||||
if (min_timeout_object) {
|
if (min_timeout_object) {
|
||||||
|
@ -79,23 +103,35 @@ namespace ams::os::impl {
|
||||||
if (min_timeout_object->IsSignaled() == TriBool::True) {
|
if (min_timeout_object->IsSignaled() == TriBool::True) {
|
||||||
std::scoped_lock lk(this->cs_wait);
|
std::scoped_lock lk(this->cs_wait);
|
||||||
this->signaled_holder = min_timeout_object;
|
this->signaled_holder = min_timeout_object;
|
||||||
return this->signaled_holder;
|
*out = min_timeout_object;
|
||||||
|
return wait_result;
|
||||||
}
|
}
|
||||||
continue;
|
} else {
|
||||||
|
*out = nullptr;
|
||||||
|
return wait_result;
|
||||||
}
|
}
|
||||||
return nullptr;
|
break;
|
||||||
case WaitCancelled:
|
case WaitCancelled:
|
||||||
if (this->signaled_holder) {
|
|
||||||
return this->signaled_holder;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
default: /* 0 - 0x3F, valid. */
|
|
||||||
{
|
{
|
||||||
|
std::scoped_lock lk(this->cs_wait);
|
||||||
|
if (this->signaled_holder) {
|
||||||
|
*out = this->signaled_holder;
|
||||||
|
return wait_result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: /* 0 - 0x3F, valid. */
|
||||||
|
{
|
||||||
|
AMS_ASSERT(0 <= index && index < static_cast<s32>(MaximumHandleCount));
|
||||||
|
|
||||||
std::scoped_lock lk(this->cs_wait);
|
std::scoped_lock lk(this->cs_wait);
|
||||||
this->signaled_holder = objects[index];
|
this->signaled_holder = objects[index];
|
||||||
return this->signaled_holder;
|
*out = objects[index];
|
||||||
|
return wait_result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reply_target = svc::InvalidHandle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,14 +38,21 @@ namespace ams::os::impl {
|
||||||
InternalCriticalSection cs_wait;
|
InternalCriticalSection cs_wait;
|
||||||
WaitableManagerTargetImpl target_impl;
|
WaitableManagerTargetImpl target_impl;
|
||||||
private:
|
private:
|
||||||
WaitableHolderBase *WaitAnyImpl(bool infinite, TimeSpan timeout);
|
Result WaitAnyImpl(WaitableHolderBase **out, bool infinite, TimeSpan timeout, bool reply, Handle reply_target);
|
||||||
WaitableHolderBase *WaitAnyHandleImpl(bool infinite, TimeSpan timeout);
|
Result WaitAnyHandleImpl(WaitableHolderBase **out, bool infinite, TimeSpan timeout, bool reply, Handle reply_target);
|
||||||
s32 BuildHandleArray(Handle out_handles[], WaitableHolderBase *out_objects[], s32 num);
|
s32 BuildHandleArray(Handle out_handles[], WaitableHolderBase *out_objects[], s32 num);
|
||||||
|
|
||||||
WaitableHolderBase *LinkHoldersToObjectList();
|
WaitableHolderBase *LinkHoldersToObjectList();
|
||||||
void UnlinkHoldersFromObjectList();
|
void UnlinkHoldersFromObjectList();
|
||||||
|
|
||||||
WaitableHolderBase *RecalculateNextTimeout(TimeSpan *out_min_timeout, TimeSpan end_time);
|
WaitableHolderBase *RecalculateNextTimeout(TimeSpan *out_min_timeout, TimeSpan end_time);
|
||||||
|
|
||||||
|
WaitableHolderBase *WaitAnyImpl(bool infinite, TimeSpan timeout) {
|
||||||
|
WaitableHolderBase *holder = nullptr;
|
||||||
|
const Result wait_result = this->WaitAnyImpl(std::addressof(holder), infinite, timeout, false, svc::InvalidHandle);
|
||||||
|
AMS_ASSERT(R_SUCCEEDED(wait_result));
|
||||||
|
return holder;
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
/* Wait. */
|
/* Wait. */
|
||||||
WaitableHolderBase *WaitAny() {
|
WaitableHolderBase *WaitAny() {
|
||||||
|
@ -60,6 +67,10 @@ namespace ams::os::impl {
|
||||||
return this->WaitAnyImpl(false, ts);
|
return this->WaitAnyImpl(false, ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result ReplyAndReceive(WaitableHolderBase **out, Handle reply_target) {
|
||||||
|
return this->WaitAnyImpl(out, true, TimeSpan::FromNanoSeconds(std::numeric_limits<s64>::max()), true, reply_target);
|
||||||
|
}
|
||||||
|
|
||||||
/* List management. */
|
/* List management. */
|
||||||
bool IsEmpty() const {
|
bool IsEmpty() const {
|
||||||
return this->waitable_list.empty();
|
return this->waitable_list.empty();
|
||||||
|
|
|
@ -19,13 +19,13 @@
|
||||||
|
|
||||||
namespace ams::os::impl {
|
namespace ams::os::impl {
|
||||||
|
|
||||||
s32 WaitableManagerHorizonImpl::WaitSynchronizationN(s32 num, Handle arr[], s32 array_size, s64 ns) {
|
Result WaitableManagerHorizonImpl::WaitSynchronizationN(s32 *out_index, s32 num, Handle arr[], s32 array_size, s64 ns) {
|
||||||
AMS_ASSERT(!(num == 0 && ns == 0));
|
AMS_ASSERT(!(num == 0 && ns == 0));
|
||||||
s32 index = WaitableManagerImpl::WaitInvalid;
|
s32 index = WaitableManagerImpl::WaitInvalid;
|
||||||
|
|
||||||
R_TRY_CATCH(svc::WaitSynchronization(std::addressof(index), static_cast<const svc::Handle *>(arr), num, ns)) {
|
R_TRY_CATCH(svc::WaitSynchronization(std::addressof(index), static_cast<const svc::Handle *>(arr), num, ns)) {
|
||||||
R_CATCH(svc::ResultTimedOut) { return WaitableManagerImpl::WaitTimedOut; }
|
R_CATCH(svc::ResultTimedOut) { index = WaitableManagerImpl::WaitTimedOut; }
|
||||||
R_CATCH(svc::ResultCancelled) { return WaitableManagerImpl::WaitCancelled; }
|
R_CATCH(svc::ResultCancelled) { index = WaitableManagerImpl::WaitCancelled; }
|
||||||
/* All other results are critical errors. */
|
/* All other results are critical errors. */
|
||||||
/* svc::ResultThreadTerminating */
|
/* svc::ResultThreadTerminating */
|
||||||
/* svc::ResultInvalidHandle. */
|
/* svc::ResultInvalidHandle. */
|
||||||
|
@ -33,7 +33,34 @@ namespace ams::os::impl {
|
||||||
/* svc::ResultOutOfRange */
|
/* svc::ResultOutOfRange */
|
||||||
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
|
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
|
||||||
|
|
||||||
return index;
|
*out_index = index;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ReplyAndReceiveN(s32 *out_index, s32 num, Handle arr[], s32 array_size, s64 ns, Handle reply_target) {
|
||||||
|
/* NOTE: Nintendo does not initialize this value, which seems like it can cause incorrect behavior. */
|
||||||
|
s32 index = WaitableManagerImpl::WaitInvalid;
|
||||||
|
static_assert(WaitableManagerImpl::WaitInvalid != -1);
|
||||||
|
|
||||||
|
R_TRY_CATCH(svc::ReplyAndReceive(std::addressof(index), arr, num, ns, reply_target)) {
|
||||||
|
R_CATCH(svc::ResultTimedOut) { *out_index = WaitableManagerImpl::WaitTimedOut; return R_CURRENT_RESULT; }
|
||||||
|
R_CATCH(svc::ResultCancelled) { *out_index = WaitableManagerImpl::WaitCancelled; return R_CURRENT_RESULT; }
|
||||||
|
R_CATCH(svc::ResultSessionClosed) {
|
||||||
|
if (index == -1) {
|
||||||
|
*out_index = WaitableManagerImpl::WaitInvalid;
|
||||||
|
return os::ResultSessionClosedForReply();
|
||||||
|
} else {
|
||||||
|
*out_index = index;
|
||||||
|
return os::ResultSessionClosedForReceive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
R_CATCH(svc::ResultReceiveListBroken) {
|
||||||
|
*out_index = index;
|
||||||
|
return os::ResultReceiveListBroken();
|
||||||
|
}
|
||||||
|
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaitableManagerHorizonImpl::CancelWait() {
|
void WaitableManagerHorizonImpl::CancelWait() {
|
||||||
|
|
|
@ -25,24 +25,33 @@ namespace ams::os::impl {
|
||||||
private:
|
private:
|
||||||
Handle handle;
|
Handle handle;
|
||||||
private:
|
private:
|
||||||
s32 WaitSynchronizationN(s32 num, Handle arr[], s32 array_size, s64 ns);
|
Result WaitSynchronizationN(s32 *out_index, s32 num, Handle arr[], s32 array_size, s64 ns);
|
||||||
|
Result ReplyAndReceiveN(s32 *out_index, s32 num, Handle arr[], s32 array_size, s64 ns, Handle reply_target);
|
||||||
public:
|
public:
|
||||||
void CancelWait();
|
void CancelWait();
|
||||||
|
|
||||||
s32 WaitAny(Handle arr[], s32 array_size, s32 num) {
|
Result WaitAny(s32 *out_index, Handle arr[], s32 array_size, s32 num) {
|
||||||
return this->WaitSynchronizationN(num, arr, array_size, svc::WaitInfinite);
|
return this->WaitSynchronizationN(out_index, num, arr, array_size, svc::WaitInfinite);
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 TryWaitAny(Handle arr[], s32 array_size, s32 num) {
|
Result TryWaitAny(s32 *out_index, Handle arr[], s32 array_size, s32 num) {
|
||||||
return this->WaitSynchronizationN(num, arr, array_size, 0);
|
return this->WaitSynchronizationN(out_index, num, arr, array_size, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 TimedWaitAny(Handle arr[], s32 array_size, s32 num, TimeSpan ts) {
|
Result TimedWaitAny(s32 *out_index, Handle arr[], s32 array_size, s32 num, TimeSpan ts) {
|
||||||
s64 timeout = ts.GetNanoSeconds();
|
s64 timeout = ts.GetNanoSeconds();
|
||||||
if (timeout < 0) {
|
if (timeout < 0) {
|
||||||
timeout = 0;
|
timeout = 0;
|
||||||
}
|
}
|
||||||
return this->WaitSynchronizationN(num, arr, array_size, timeout);
|
return this->WaitSynchronizationN(out_index, num, arr, array_size, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ReplyAndReceive(s32 *out_index, Handle arr[], s32 array_size, s32 num, Handle reply_target) {
|
||||||
|
return this->ReplyAndReceiveN(out_index, num, arr, array_size, std::numeric_limits<s64>::max(), reply_target);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result TimedReplyAndReceive(s32 *out_index, Handle arr[], s32 array_size, s32 num, Handle reply_target, TimeSpan ts) {
|
||||||
|
return this->ReplyAndReceiveN(out_index, num, arr, array_size, ts.GetNanoSeconds(), reply_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetCurrentThreadHandleForCancelWait() {
|
void SetCurrentThreadHandleForCancelWait() {
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "impl/os_waitable_manager_impl.hpp"
|
||||||
|
#include "impl/os_waitable_holder_base.hpp"
|
||||||
|
#include "impl/os_waitable_holder_impl.hpp"
|
||||||
|
|
||||||
|
namespace ams::os {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
ALWAYS_INLINE impl::WaitableManagerImpl &GetWaitableManagerImpl(WaitableManagerType *manager) {
|
||||||
|
return GetReference(manager->impl_storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE WaitableHolderType *CastToWaitableHolder(impl::WaitableHolderBase *base) {
|
||||||
|
return reinterpret_cast<WaitableHolderType *>(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SdkReplyAndReceive(os::WaitableHolderType **out, Handle reply_target, WaitableManagerType *manager) {
|
||||||
|
auto &impl = GetWaitableManagerImpl(manager);
|
||||||
|
|
||||||
|
AMS_ASSERT(manager->state == WaitableManagerType::State_Initialized);
|
||||||
|
AMS_ASSERT(!impl.IsEmpty());
|
||||||
|
|
||||||
|
impl::WaitableHolderBase *holder_base;
|
||||||
|
ON_SCOPE_EXIT { *out = CastToWaitableHolder(holder_base); };
|
||||||
|
|
||||||
|
return impl.ReplyAndReceive(std::addressof(holder_base), reply_target);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -26,7 +26,7 @@ namespace ams::os {
|
||||||
return GetReference(manager->impl_storage);
|
return GetReference(manager->impl_storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE WaitableHolderType *ReinterpretAsWaitableHolder(impl::WaitableHolderBase *base) {
|
ALWAYS_INLINE WaitableHolderType *CastToWaitableHolder(impl::WaitableHolderBase *base) {
|
||||||
return reinterpret_cast<WaitableHolderType *>(base);
|
return reinterpret_cast<WaitableHolderType *>(base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ namespace ams::os {
|
||||||
AMS_ASSERT(manager->state == WaitableManagerType::State_Initialized);
|
AMS_ASSERT(manager->state == WaitableManagerType::State_Initialized);
|
||||||
AMS_ASSERT(!impl.IsEmpty());
|
AMS_ASSERT(!impl.IsEmpty());
|
||||||
|
|
||||||
auto *holder = ReinterpretAsWaitableHolder(impl.WaitAny());
|
auto *holder = CastToWaitableHolder(impl.WaitAny());
|
||||||
AMS_ASSERT(holder != nullptr);
|
AMS_ASSERT(holder != nullptr);
|
||||||
return holder;
|
return holder;
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ namespace ams::os {
|
||||||
AMS_ASSERT(manager->state == WaitableManagerType::State_Initialized);
|
AMS_ASSERT(manager->state == WaitableManagerType::State_Initialized);
|
||||||
AMS_ASSERT(!impl.IsEmpty());
|
AMS_ASSERT(!impl.IsEmpty());
|
||||||
|
|
||||||
auto *holder = ReinterpretAsWaitableHolder(impl.TryWaitAny());
|
auto *holder = CastToWaitableHolder(impl.TryWaitAny());
|
||||||
return holder;
|
return holder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ namespace ams::os {
|
||||||
AMS_ASSERT(!impl.IsEmpty());
|
AMS_ASSERT(!impl.IsEmpty());
|
||||||
AMS_ASSERT(timeout.GetNanoSeconds() >= 0);
|
AMS_ASSERT(timeout.GetNanoSeconds() >= 0);
|
||||||
|
|
||||||
auto *holder = ReinterpretAsWaitableHolder(impl.TimedWaitAny(timeout));
|
auto *holder = CastToWaitableHolder(impl.TimedWaitAny(timeout));
|
||||||
return holder;
|
return holder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,4 +37,8 @@ namespace ams::os {
|
||||||
R_DEFINE_ERROR_RESULT(OutOfTransferMemory, 505);
|
R_DEFINE_ERROR_RESULT(OutOfTransferMemory, 505);
|
||||||
R_DEFINE_ERROR_RESULT(OutOfAddressSpace, 506);
|
R_DEFINE_ERROR_RESULT(OutOfAddressSpace, 506);
|
||||||
|
|
||||||
|
R_DEFINE_ERROR_RESULT(SessionClosedForReceive, 510);
|
||||||
|
R_DEFINE_ERROR_RESULT(SessionClosedForReply, 511);
|
||||||
|
R_DEFINE_ERROR_RESULT(ReceiveListBroken, 512);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue