mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 12:21:18 +00:00
kern/svc: update WaitForAddress to support 64-bit WaitIfEqual
This commit is contained in:
parent
5de551db29
commit
a0ad3ef949
11 changed files with 163 additions and 13 deletions
|
@ -25,6 +25,7 @@ namespace ams::kern::arch::arm64 {
|
||||||
static bool CopyMemoryFromUser(void *dst, const void *src, size_t size);
|
static bool CopyMemoryFromUser(void *dst, const void *src, size_t size);
|
||||||
static bool CopyMemoryFromUserAligned32Bit(void *dst, const void *src, size_t size);
|
static bool CopyMemoryFromUserAligned32Bit(void *dst, const void *src, size_t size);
|
||||||
static bool CopyMemoryFromUserAligned64Bit(void *dst, const void *src, size_t size);
|
static bool CopyMemoryFromUserAligned64Bit(void *dst, const void *src, size_t size);
|
||||||
|
static bool CopyMemoryFromUserSize64Bit(void *dst, const void *src);
|
||||||
static bool CopyMemoryFromUserSize32Bit(void *dst, const void *src);
|
static bool CopyMemoryFromUserSize32Bit(void *dst, const void *src);
|
||||||
static s32 CopyStringFromUser(void *dst, const void *src, size_t size);
|
static s32 CopyStringFromUser(void *dst, const void *src, size_t size);
|
||||||
|
|
||||||
|
|
|
@ -39,14 +39,16 @@ namespace ams::kern {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result WaitForAddress(uintptr_t addr, ams::svc::ArbitrationType type, s32 value, s64 timeout) {
|
Result WaitForAddress(uintptr_t addr, ams::svc::ArbitrationType type, s64 value, s64 timeout) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ams::svc::ArbitrationType_WaitIfLessThan:
|
case ams::svc::ArbitrationType_WaitIfLessThan:
|
||||||
R_RETURN(this->WaitIfLessThan(addr, value, false, timeout));
|
R_RETURN(this->WaitIfLessThan(addr, static_cast<s32>(value), false, timeout));
|
||||||
case ams::svc::ArbitrationType_DecrementAndWaitIfLessThan:
|
case ams::svc::ArbitrationType_DecrementAndWaitIfLessThan:
|
||||||
R_RETURN(this->WaitIfLessThan(addr, value, true, timeout));
|
R_RETURN(this->WaitIfLessThan(addr, static_cast<s32>(value), true, timeout));
|
||||||
case ams::svc::ArbitrationType_WaitIfEqual:
|
case ams::svc::ArbitrationType_WaitIfEqual:
|
||||||
R_RETURN(this->WaitIfEqual(addr, value, timeout));
|
R_RETURN(this->WaitIfEqual(addr, static_cast<s32>(value), timeout));
|
||||||
|
case ams::svc::ArbitrationType_WaitIfEqual64:
|
||||||
|
R_RETURN(this->WaitIfEqual64(addr, value, timeout));
|
||||||
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,6 +58,7 @@ namespace ams::kern {
|
||||||
Result SignalAndModifyByWaitingCountIfEqual(uintptr_t addr, s32 value, s32 count);
|
Result SignalAndModifyByWaitingCountIfEqual(uintptr_t addr, s32 value, s32 count);
|
||||||
Result WaitIfLessThan(uintptr_t addr, s32 value, bool decrement, s64 timeout);
|
Result WaitIfLessThan(uintptr_t addr, s32 value, bool decrement, s64 timeout);
|
||||||
Result WaitIfEqual(uintptr_t addr, s32 value, s64 timeout);
|
Result WaitIfEqual(uintptr_t addr, s32 value, s64 timeout);
|
||||||
|
Result WaitIfEqual64(uintptr_t addr, s64 value, s64 timeout);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -360,7 +360,7 @@ namespace ams::kern {
|
||||||
R_RETURN(m_address_arbiter.SignalToAddress(address, signal_type, value, count));
|
R_RETURN(m_address_arbiter.SignalToAddress(address, signal_type, value, count));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result WaitAddressArbiter(uintptr_t address, ams::svc::ArbitrationType arb_type, s32 value, s64 timeout) {
|
Result WaitAddressArbiter(uintptr_t address, ams::svc::ArbitrationType arb_type, s64 value, s64 timeout) {
|
||||||
R_RETURN(m_address_arbiter.WaitForAddress(address, arb_type, value, timeout));
|
R_RETURN(m_address_arbiter.WaitForAddress(address, arb_type, value, timeout));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -126,6 +126,20 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess30CopyMemoryFromUserAligned64BitEPvPKvm:
|
||||||
mov x0, #1
|
mov x0, #1
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
/* ams::kern::arch::arm64::UserspaceAccess::CopyMemoryFromUserSize64Bit(void *dst, const void *src) */
|
||||||
|
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize64BitEPvPKv, "ax", %progbits
|
||||||
|
.global _ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize64BitEPvPKv
|
||||||
|
.type _ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize64BitEPvPKv, %function
|
||||||
|
.balign 0x10
|
||||||
|
_ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize64BitEPvPKv:
|
||||||
|
/* Just load and store a u64. */
|
||||||
|
ldtr x2, [x1]
|
||||||
|
str x2, [x0]
|
||||||
|
|
||||||
|
/* We're done. */
|
||||||
|
mov x0, #1
|
||||||
|
ret
|
||||||
|
|
||||||
/* ams::kern::arch::arm64::UserspaceAccess::CopyMemoryFromUserSize32Bit(void *dst, const void *src) */
|
/* ams::kern::arch::arm64::UserspaceAccess::CopyMemoryFromUserSize32Bit(void *dst, const void *src) */
|
||||||
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize32BitEPvPKv, "ax", %progbits
|
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize32BitEPvPKv, "ax", %progbits
|
||||||
.global _ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize32BitEPvPKv
|
.global _ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize32BitEPvPKv
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ams::kern::svc::CallWaitForAddress64From32() */
|
||||||
|
.section .text._ZN3ams4kern3svc26CallWaitForAddress64From32Ev, "ax", %progbits
|
||||||
|
.global _ZN3ams4kern3svc26CallWaitForAddress64From32Ev
|
||||||
|
.type _ZN3ams4kern3svc26CallWaitForAddress64From32Ev, %function
|
||||||
|
_ZN3ams4kern3svc26CallWaitForAddress64From32Ev:
|
||||||
|
/* Save LR + callee-save registers. */
|
||||||
|
str x30, [sp, #-16]!
|
||||||
|
stp x6, x7, [sp, #-16]!
|
||||||
|
|
||||||
|
/* Gather the arguments into correct registers. */
|
||||||
|
/* NOTE: This has to be manually implemented via asm, */
|
||||||
|
/* in order to avoid breaking ABI with pre-19.0.0. */
|
||||||
|
orr x2, x2, x5, lsl#32
|
||||||
|
orr x3, x3, x4, lsl#32
|
||||||
|
|
||||||
|
/* Invoke the svc handler. */
|
||||||
|
bl _ZN3ams4kern3svc22WaitForAddress64From32ENS_3svc7AddressENS2_15ArbitrationTypeEll
|
||||||
|
|
||||||
|
/* Clean up registers. */
|
||||||
|
mov x1, xzr
|
||||||
|
mov x2, xzr
|
||||||
|
mov x3, xzr
|
||||||
|
mov x4, xzr
|
||||||
|
mov x5, xzr
|
||||||
|
|
||||||
|
ldp x6, x7, [sp], #0x10
|
||||||
|
ldr x30, [sp], #0x10
|
||||||
|
ret
|
||||||
|
|
||||||
|
/* ams::kern::svc::CallWaitForAddress64() */
|
||||||
|
.section .text._ZN3ams4kern3svc20CallWaitForAddress64Ev, "ax", %progbits
|
||||||
|
.global _ZN3ams4kern3svc20CallWaitForAddress64Ev
|
||||||
|
.type _ZN3ams4kern3svc20CallWaitForAddress64Ev, %function
|
||||||
|
_ZN3ams4kern3svc20CallWaitForAddress64Ev:
|
||||||
|
/* Save LR + FP. */
|
||||||
|
stp x29, x30, [sp, #-16]!
|
||||||
|
|
||||||
|
/* Invoke the svc handler. */
|
||||||
|
bl _ZN3ams4kern3svc22WaitForAddress64From32ENS_3svc7AddressENS2_15ArbitrationTypeEll
|
||||||
|
|
||||||
|
/* Clean up registers. */
|
||||||
|
mov x1, xzr
|
||||||
|
mov x2, xzr
|
||||||
|
mov x3, xzr
|
||||||
|
mov x4, xzr
|
||||||
|
mov x5, xzr
|
||||||
|
mov x6, xzr
|
||||||
|
mov x7, xzr
|
||||||
|
|
||||||
|
ldp x29, x30, [sp], #0x10
|
||||||
|
ret
|
|
@ -36,6 +36,10 @@ namespace ams::kern::svc {
|
||||||
/* Declare special prototype for (unsupported) CallCallSecureMonitor64From32. */
|
/* Declare special prototype for (unsupported) CallCallSecureMonitor64From32. */
|
||||||
void CallCallSecureMonitor64From32();
|
void CallCallSecureMonitor64From32();
|
||||||
|
|
||||||
|
/* Declare special prototypes for WaitForAddress. */
|
||||||
|
void CallWaitForAddress64();
|
||||||
|
void CallWaitForAddress64From32();
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
#ifndef MESOSPHERE_USE_STUBBED_SVC_TABLES
|
#ifndef MESOSPHERE_USE_STUBBED_SVC_TABLES
|
||||||
|
@ -81,6 +85,8 @@ namespace ams::kern::svc {
|
||||||
|
|
||||||
table[svc::SvcId_CallSecureMonitor] = CallCallSecureMonitor64From32;
|
table[svc::SvcId_CallSecureMonitor] = CallCallSecureMonitor64From32;
|
||||||
|
|
||||||
|
table[svc::SvcId_WaitForAddress] = CallWaitForAddress64From32;
|
||||||
|
|
||||||
return table;
|
return table;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
|
@ -97,6 +103,8 @@ namespace ams::kern::svc {
|
||||||
|
|
||||||
table[svc::SvcId_ReturnFromException] = CallReturnFromException64;
|
table[svc::SvcId_ReturnFromException] = CallReturnFromException64;
|
||||||
|
|
||||||
|
table[svc::SvcId_WaitForAddress] = CallWaitForAddress64;
|
||||||
|
|
||||||
return table;
|
return table;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,10 @@ namespace ams::kern {
|
||||||
return UserspaceAccess::CopyMemoryFromUserSize32Bit(out, GetVoidPointer(address));
|
return UserspaceAccess::CopyMemoryFromUserSize32Bit(out, GetVoidPointer(address));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE bool ReadFromUser(s64 *out, KProcessAddress address) {
|
||||||
|
return UserspaceAccess::CopyMemoryFromUserSize64Bit(out, GetVoidPointer(address));
|
||||||
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE bool DecrementIfLessThan(s32 *out, KProcessAddress address, s32 value) {
|
ALWAYS_INLINE bool DecrementIfLessThan(s32 *out, KProcessAddress address, s32 value) {
|
||||||
/* NOTE: If scheduler lock is not held here, interrupt disable is required. */
|
/* NOTE: If scheduler lock is not held here, interrupt disable is required. */
|
||||||
/* KScopedInterruptDisable di; */
|
/* KScopedInterruptDisable di; */
|
||||||
|
@ -279,4 +283,51 @@ namespace ams::kern {
|
||||||
R_RETURN(cur_thread->GetWaitResult());
|
R_RETURN(cur_thread->GetWaitResult());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result KAddressArbiter::WaitIfEqual64(uintptr_t addr, s64 value, s64 timeout) {
|
||||||
|
/* Prepare to wait. */
|
||||||
|
KThread *cur_thread = GetCurrentThreadPointer();
|
||||||
|
KHardwareTimer *timer;
|
||||||
|
ThreadQueueImplForKAddressArbiter wait_queue(std::addressof(m_tree));
|
||||||
|
|
||||||
|
{
|
||||||
|
KScopedSchedulerLockAndSleep slp(std::addressof(timer), cur_thread, timeout);
|
||||||
|
|
||||||
|
/* Check that the thread isn't terminating. */
|
||||||
|
if (cur_thread->IsTerminationRequested()) {
|
||||||
|
slp.CancelSleep();
|
||||||
|
R_THROW(svc::ResultTerminationRequested());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the value from userspace. */
|
||||||
|
s64 user_value;
|
||||||
|
if (!ReadFromUser(std::addressof(user_value), addr)) {
|
||||||
|
slp.CancelSleep();
|
||||||
|
R_THROW(svc::ResultInvalidCurrentMemory());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the value is equal. */
|
||||||
|
if (value != user_value) {
|
||||||
|
slp.CancelSleep();
|
||||||
|
R_THROW(svc::ResultInvalidState());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the timeout is non-zero. */
|
||||||
|
if (timeout == 0) {
|
||||||
|
slp.CancelSleep();
|
||||||
|
R_THROW(svc::ResultTimedOut());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the arbiter. */
|
||||||
|
cur_thread->SetAddressArbiter(std::addressof(m_tree), addr);
|
||||||
|
m_tree.insert(*cur_thread);
|
||||||
|
|
||||||
|
/* Wait for the thread to finish. */
|
||||||
|
wait_queue.SetHardwareTimer(timer);
|
||||||
|
cur_thread->BeginWait(std::addressof(wait_queue));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the wait result. */
|
||||||
|
R_RETURN(cur_thread->GetWaitResult());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,16 +41,21 @@ namespace ams::kern::svc {
|
||||||
case ams::svc::ArbitrationType_WaitIfLessThan:
|
case ams::svc::ArbitrationType_WaitIfLessThan:
|
||||||
case ams::svc::ArbitrationType_DecrementAndWaitIfLessThan:
|
case ams::svc::ArbitrationType_DecrementAndWaitIfLessThan:
|
||||||
case ams::svc::ArbitrationType_WaitIfEqual:
|
case ams::svc::ArbitrationType_WaitIfEqual:
|
||||||
|
case ams::svc::ArbitrationType_WaitIfEqual64:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result WaitForAddress(uintptr_t address, ams::svc::ArbitrationType arb_type, int32_t value, int64_t timeout_ns) {
|
Result WaitForAddress(uintptr_t address, ams::svc::ArbitrationType arb_type, int64_t value, int64_t timeout_ns) {
|
||||||
/* Validate input. */
|
/* Validate input. */
|
||||||
R_UNLESS(AMS_LIKELY(!IsKernelAddress(address)), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(AMS_LIKELY(!IsKernelAddress(address)), svc::ResultInvalidCurrentMemory());
|
||||||
|
if (arb_type == ams::svc::ArbitrationType_WaitIfEqual64) {
|
||||||
|
R_UNLESS(util::IsAligned(address, sizeof(int64_t)), svc::ResultInvalidAddress());
|
||||||
|
} else {
|
||||||
R_UNLESS(util::IsAligned(address, sizeof(int32_t)), svc::ResultInvalidAddress());
|
R_UNLESS(util::IsAligned(address, sizeof(int32_t)), svc::ResultInvalidAddress());
|
||||||
|
}
|
||||||
R_UNLESS(IsValidArbitrationType(arb_type), svc::ResultInvalidEnumValue());
|
R_UNLESS(IsValidArbitrationType(arb_type), svc::ResultInvalidEnumValue());
|
||||||
|
|
||||||
/* Convert timeout from nanoseconds to ticks. */
|
/* Convert timeout from nanoseconds to ticks. */
|
||||||
|
@ -85,7 +90,7 @@ namespace ams::kern::svc {
|
||||||
|
|
||||||
/* ============================= 64 ABI ============================= */
|
/* ============================= 64 ABI ============================= */
|
||||||
|
|
||||||
Result WaitForAddress64(ams::svc::Address address, ams::svc::ArbitrationType arb_type, int32_t value, int64_t timeout_ns) {
|
Result WaitForAddress64(ams::svc::Address address, ams::svc::ArbitrationType arb_type, int64_t value, int64_t timeout_ns) {
|
||||||
R_RETURN(WaitForAddress(address, arb_type, value, timeout_ns));
|
R_RETURN(WaitForAddress(address, arb_type, value, timeout_ns));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +100,7 @@ namespace ams::kern::svc {
|
||||||
|
|
||||||
/* ============================= 64From32 ABI ============================= */
|
/* ============================= 64From32 ABI ============================= */
|
||||||
|
|
||||||
Result WaitForAddress64From32(ams::svc::Address address, ams::svc::ArbitrationType arb_type, int32_t value, int64_t timeout_ns) {
|
Result WaitForAddress64From32(ams::svc::Address address, ams::svc::ArbitrationType arb_type, int64_t value, int64_t timeout_ns) {
|
||||||
R_RETURN(WaitForAddress(address, arb_type, value, timeout_ns));
|
R_RETURN(WaitForAddress(address, arb_type, value, timeout_ns));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -231,7 +231,7 @@
|
||||||
R_RETURN(::svcGetThreadContext3(reinterpret_cast<::ThreadContext *>(out_context.GetPointerUnsafe()), thread_handle));
|
R_RETURN(::svcGetThreadContext3(reinterpret_cast<::ThreadContext *>(out_context.GetPointerUnsafe()), thread_handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE Result WaitForAddress(::ams::svc::Address address, ::ams::svc::ArbitrationType arb_type, int32_t value, int64_t timeout_ns) {
|
ALWAYS_INLINE Result WaitForAddress(::ams::svc::Address address, ::ams::svc::ArbitrationType arb_type, int64_t value, int64_t timeout_ns) {
|
||||||
R_RETURN(::svcWaitForAddress(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), arb_type, value, timeout_ns));
|
R_RETURN(::svcWaitForAddress(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), arb_type, value, timeout_ns));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@
|
||||||
HANDLER(0x31, Result, GetResourceLimitCurrentValue, OUTPUT(int64_t, out_current_value), INPUT(::ams::svc::Handle, resource_limit_handle), INPUT(::ams::svc::LimitableResource, which)) \
|
HANDLER(0x31, Result, GetResourceLimitCurrentValue, OUTPUT(int64_t, out_current_value), INPUT(::ams::svc::Handle, resource_limit_handle), INPUT(::ams::svc::LimitableResource, which)) \
|
||||||
HANDLER(0x32, Result, SetThreadActivity, INPUT(::ams::svc::Handle, thread_handle), INPUT(::ams::svc::ThreadActivity, thread_activity)) \
|
HANDLER(0x32, Result, SetThreadActivity, INPUT(::ams::svc::Handle, thread_handle), INPUT(::ams::svc::ThreadActivity, thread_activity)) \
|
||||||
HANDLER(0x33, Result, GetThreadContext3, OUTPTR(::ams::svc::ThreadContext, out_context), INPUT(::ams::svc::Handle, thread_handle)) \
|
HANDLER(0x33, Result, GetThreadContext3, OUTPTR(::ams::svc::ThreadContext, out_context), INPUT(::ams::svc::Handle, thread_handle)) \
|
||||||
HANDLER(0x34, Result, WaitForAddress, INPUT(::ams::svc::Address, address), INPUT(::ams::svc::ArbitrationType, arb_type), INPUT(int32_t, value), INPUT(int64_t, timeout_ns)) \
|
HANDLER(0x34, Result, WaitForAddress, INPUT(::ams::svc::Address, address), INPUT(::ams::svc::ArbitrationType, arb_type), INPUT(int64_t, value), INPUT(int64_t, timeout_ns)) \
|
||||||
HANDLER(0x35, Result, SignalToAddress, INPUT(::ams::svc::Address, address), INPUT(::ams::svc::SignalType, signal_type), INPUT(int32_t, value), INPUT(int32_t, count)) \
|
HANDLER(0x35, Result, SignalToAddress, INPUT(::ams::svc::Address, address), INPUT(::ams::svc::SignalType, signal_type), INPUT(int32_t, value), INPUT(int32_t, count)) \
|
||||||
HANDLER(0x36, void, SynchronizePreemptionState) \
|
HANDLER(0x36, void, SynchronizePreemptionState) \
|
||||||
HANDLER(0x37, Result, GetResourceLimitPeakValue, OUTPUT(int64_t, out_peak_value), INPUT(::ams::svc::Handle, resource_limit_handle), INPUT(::ams::svc::LimitableResource, which)) \
|
HANDLER(0x37, Result, GetResourceLimitPeakValue, OUTPUT(int64_t, out_peak_value), INPUT(::ams::svc::Handle, resource_limit_handle), INPUT(::ams::svc::LimitableResource, which)) \
|
||||||
|
|
|
@ -263,6 +263,7 @@ namespace ams::svc {
|
||||||
ArbitrationType_WaitIfLessThan = 0,
|
ArbitrationType_WaitIfLessThan = 0,
|
||||||
ArbitrationType_DecrementAndWaitIfLessThan = 1,
|
ArbitrationType_DecrementAndWaitIfLessThan = 1,
|
||||||
ArbitrationType_WaitIfEqual = 2,
|
ArbitrationType_WaitIfEqual = 2,
|
||||||
|
ArbitrationType_WaitIfEqual64 = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum YieldType : s64 {
|
enum YieldType : s64 {
|
||||||
|
|
Loading…
Reference in a new issue