2023-03-12 15:27:28 +00:00
/***
Copyright ( C ) 2023 J Reece Wilson ( a / k / a " Reece " ) . All rights reserved .
File : AuWakeOnAddress . cpp
Date : 2023 - 3 - 10
Author : Reece
* * */
2024-03-12 22:50:22 +00:00
# if defined(AURORA_COMPILER_MSVC)
# pragma strict_gs_check(off)
# pragma check_stack(off)
# endif
2023-03-12 15:27:28 +00:00
# include <Source/RuntimeInternal.hpp>
# include "AuWakeOnAddress.hpp"
2023-03-21 03:18:09 +00:00
# include "Primitives/SMTYield.hpp"
2023-07-06 08:37:58 +00:00
2023-06-15 19:44:27 +00:00
# include <Time/Time.hpp>
2023-07-05 17:25:07 +00:00
# define HACK_NO_INVALID_ACCESS_LEAK_SHARED_REF_ON_DESTROYED_THREAD
2023-12-21 15:54:05 +00:00
// WOA_ALWAYS_DUMB_OS_TARGET -> iOS, notarized MacOS, Win9x, Xbox 360, etc
2023-07-05 17:25:07 +00:00
2024-11-21 17:17:09 +00:00
// This will tank the average case:
// > fast paths will be disabled,
// > lock barriers turn into full lock guards,
// > and every sleep will require a condvar or semaphore wakeup.
// Every perf trick will be bypassed.
2024-11-24 05:05:02 +00:00
// Update: partially removed. its not ready yet
2024-11-21 17:17:09 +00:00
//#define WOA_STRICTER_FIFO
2023-03-21 03:18:09 +00:00
namespace Aurora : : Threading
2023-03-12 15:27:28 +00:00
{
2023-07-05 17:25:07 +00:00
# if defined(HACK_NO_INVALID_ACCESS_LEAK_SHARED_REF_ON_DESTROYED_THREAD)
static thread_local AuSPtr < WaitEntry > tlsWaitEntry = AuMakeSharedPanic < WaitEntry > ( ) ;
# else
2023-06-11 18:13:37 +00:00
static thread_local WaitEntry tlsWaitEntry ;
2023-07-05 17:25:07 +00:00
# endif
2023-06-11 18:13:37 +00:00
2024-03-12 22:50:22 +00:00
# define DO_OF_METHOD_TYPE(preface, DoOfMethodType, ...) \
switch ( eMethod ) \
{ \
case EWaitMethod : : eNotEqual : \
preface DoOfMethodType < EWaitMethod : : eNotEqual > ( __VA_ARGS__ ) ; \
break ; \
case EWaitMethod : : eEqual : \
preface DoOfMethodType < EWaitMethod : : eEqual > ( __VA_ARGS__ ) ; \
break ; \
case EWaitMethod : : eGreaterThanCompare : \
preface DoOfMethodType < EWaitMethod : : eGreaterThanCompare > ( __VA_ARGS__ ) ; \
break ; \
case EWaitMethod : : eGreaterThanOrEqualsCompare : \
preface DoOfMethodType < EWaitMethod : : eGreaterThanOrEqualsCompare > ( __VA_ARGS__ ) ; \
break ; \
case EWaitMethod : : eLessThanCompare : \
preface DoOfMethodType < EWaitMethod : : eLessThanCompare > ( __VA_ARGS__ ) ; \
break ; \
case EWaitMethod : : eLessThanOrEqualsCompare : \
preface DoOfMethodType < EWaitMethod : : eLessThanOrEqualsCompare > ( __VA_ARGS__ ) ; \
break ; \
2024-11-14 11:18:47 +00:00
case EWaitMethod : : eAnd : \
preface DoOfMethodType < EWaitMethod : : eAnd > ( __VA_ARGS__ ) ; \
break ; \
case EWaitMethod : : eNotAnd : \
preface DoOfMethodType < EWaitMethod : : eNotAnd > ( __VA_ARGS__ ) ; \
break ; \
2024-03-12 22:50:22 +00:00
}
2024-04-28 13:13:09 +00:00
static const int gShouldSpinOnlyInCPU = 1 ; // TODO: havent decided
// UPDATE: 1 paranoia just in case we get preempted (rare).
2023-06-11 18:13:37 +00:00
template < typename T >
static void DoSpinLockOnVar ( T * uPointer )
2023-03-12 15:27:28 +00:00
{
2023-06-11 18:13:37 +00:00
if ( gShouldSpinOnlyInCPU = = 0 )
{
2024-05-03 11:14:52 +00:00
while ( ! Primitives : : DoTryIfAlderLake ( [ & ] ( )
2023-06-11 18:13:37 +00:00
{
return AuAtomicTestAndSet ( uPointer , 0 ) = = 0 ;
2024-05-03 11:14:52 +00:00
} , uPointer ) )
2023-06-11 18:13:37 +00:00
{
}
}
else if ( gShouldSpinOnlyInCPU = = 1 )
{
2024-05-03 11:14:52 +00:00
while ( ! Primitives : : DoTryIfAlderLake ( [ & ] ( )
2023-06-11 18:13:37 +00:00
{
return AuAtomicTestAndSet ( uPointer , 0 ) = = 0 ;
2024-05-03 11:14:52 +00:00
} , uPointer ) )
2023-06-11 18:13:37 +00:00
{
ContextYield ( ) ;
}
}
else if ( gShouldSpinOnlyInCPU = = 2 )
2023-03-12 15:27:28 +00:00
{
2023-06-11 18:13:37 +00:00
while ( AuAtomicTestAndSet ( uPointer , 0 ) )
2023-03-12 15:27:28 +00:00
{
2023-06-11 18:13:37 +00:00
while ( * uPointer )
{
ContextYield ( ) ;
}
2023-03-12 15:27:28 +00:00
}
}
2023-06-11 18:13:37 +00:00
else
{
SysUnreachable ( ) ;
}
}
2023-03-12 15:27:28 +00:00
void WaitEntry : : Release ( )
{
AuResetMember ( this - > uSize ) ;
AuResetMember ( this - > pAddress ) ;
}
2023-11-17 23:06:08 +00:00
2023-08-21 16:34:24 +00:00
WaitEntry : : WaitEntry ( )
2023-03-12 15:27:28 +00:00
{
}
WaitEntry : : ~ WaitEntry ( )
{
this - > Release ( ) ;
}
2024-03-12 22:50:22 +00:00
template < EWaitMethod eMethod >
2023-03-12 15:27:28 +00:00
bool WaitEntry : : SleepOn ( WaitState & state )
{
2023-12-10 19:25:31 +00:00
# if !defined(WOA_SEMAPHORE_MODE)
2023-03-12 15:27:28 +00:00
AU_LOCK_GUARD ( this - > mutex ) ;
2023-12-10 19:25:31 +00:00
# endif
2023-11-17 23:06:08 +00:00
2023-06-15 19:44:27 +00:00
if ( state . qwNanosecondsAbs )
2023-03-12 15:27:28 +00:00
{
2024-03-12 22:50:22 +00:00
if ( ! WaitBuffer : : Compare2 < eMethod , true > ( this - > pAddress , this - > uSize , state . compare . buffer , state . uDownsizeMask ) )
2023-03-12 15:27:28 +00:00
{
return true ;
}
auto uNow = AuTime : : SteadyClockNS ( ) ;
2023-07-06 08:43:28 +00:00
auto uEndTime = state . qwNanosecondsAbs . value ( ) ;
2023-03-12 15:27:28 +00:00
while ( uNow < uEndTime )
{
2024-03-12 22:50:22 +00:00
if ( ! WaitBuffer : : Compare2 < eMethod , true > ( this - > pAddress , this - > uSize , state . compare . buffer , state . uDownsizeMask ) )
2023-03-12 15:27:28 +00:00
{
return true ;
}
2023-05-08 14:16:06 +00:00
# if defined(AURORA_PLATFORM_WIN32)
2023-07-09 11:34:14 +00:00
Win32DropSchedulerResolution ( ) ;
2023-05-08 14:16:06 +00:00
# endif
2023-11-17 23:06:08 +00:00
2024-06-23 03:08:58 +00:00
// potentially release/acquire-less by virtue of the lockless semaphore mode
if ( ! AuAtomicLoad ( & this - > bAlive ) )
2023-12-10 18:21:35 +00:00
{
2023-12-10 20:01:06 +00:00
# if !defined(WOA_SEMAPHORE_MODE)
this - > mutex . Unlock ( ) ;
# endif
2024-03-12 22:50:22 +00:00
( void ) gProcessWaitables . WaitBufferFrom ( this - > pAddress , this - > uSize , false , state . pCompare2 , eMethod ) ;
2023-12-10 20:01:06 +00:00
# if !defined(WOA_SEMAPHORE_MODE)
this - > mutex . Lock ( ) ;
# endif
2024-11-21 17:17:09 +00:00
# if defined(WOA_STRICTER_FIFO)
if ( ! WaitBuffer : : Compare2 < eMethod , true > ( this - > pAddress , this - > uSize , state . compare . buffer , state . uDownsizeMask ) )
{
return true ;
}
# endif
continue ;
2023-12-10 18:21:35 +00:00
}
2024-11-21 17:17:09 +00:00
2023-12-10 18:21:35 +00:00
{
2023-12-10 19:25:31 +00:00
# if defined(WOA_SEMAPHORE_MODE)
this - > semaphore - > LockAbsNS ( uEndTime ) ;
# else
auto uTimeRemNS = uEndTime - uNow ;
2023-12-10 20:01:06 +00:00
this - > variable . WaitForSignalNsEx ( & this - > mutex , uTimeRemNS , false ) ;
2023-12-10 19:25:31 +00:00
# endif
2023-12-10 18:21:35 +00:00
}
2023-03-12 15:27:28 +00:00
uNow = AuTime : : SteadyClockNS ( ) ;
}
2024-03-12 22:50:22 +00:00
return ! WaitBuffer : : Compare2 < eMethod , true > ( this - > pAddress , this - > uSize , state . compare . buffer , state . uDownsizeMask ) ;
2023-03-12 15:27:28 +00:00
}
else
{
2024-03-12 22:50:22 +00:00
while ( WaitBuffer : : Compare2 < eMethod , true > ( this - > pAddress , this - > uSize , state . compare . buffer , state . uDownsizeMask ) )
2023-03-12 15:27:28 +00:00
{
2024-06-23 03:08:58 +00:00
if ( ! AuAtomicLoad ( & this - > bAlive ) )
2023-12-10 18:21:35 +00:00
{
2023-12-10 20:01:06 +00:00
# if !defined(WOA_SEMAPHORE_MODE)
this - > mutex . Unlock ( ) ;
# endif
2024-03-12 22:50:22 +00:00
( void ) gProcessWaitables . WaitBufferFrom ( this - > pAddress , this - > uSize , false , state . pCompare2 , eMethod ) ;
2023-12-10 20:01:06 +00:00
# if !defined(WOA_SEMAPHORE_MODE)
this - > mutex . Lock ( ) ;
# endif
2024-11-21 17:17:09 +00:00
continue ;
2023-12-10 18:21:35 +00:00
}
2024-11-21 17:17:09 +00:00
2023-12-10 18:21:35 +00:00
{
2023-12-10 19:25:31 +00:00
# if defined(WOA_SEMAPHORE_MODE)
this - > semaphore - > Lock ( ) ;
# else
2023-12-10 20:01:06 +00:00
this - > variable . WaitForSignalNsEx ( & this - > mutex , 0 , false ) ;
2023-12-10 19:25:31 +00:00
# endif
2023-12-10 18:21:35 +00:00
}
2023-03-12 15:27:28 +00:00
}
return true ;
}
return false ;
}
2023-12-05 07:56:57 +00:00
bool WaitEntry : : TrySignalAddress ( const void * pAddress )
2023-03-12 15:27:28 +00:00
{
2023-07-30 08:34:39 +00:00
if ( this - > pAddress ! = pAddress )
{
return false ;
}
2023-03-12 15:27:28 +00:00
2024-03-02 23:23:16 +00:00
if ( this - > pCompareAddress )
{
2024-03-12 22:50:22 +00:00
if ( WaitBuffer : : Compare ( pAddress , this - > uSize , this - > pCompareAddress , kMax64 , this - > eWaitMethod ) )
2024-03-02 23:23:16 +00:00
{
return false ;
}
}
2023-12-10 19:25:31 +00:00
# if defined(WOA_SEMAPHORE_MODE)
this - > semaphore - > Unlock ( 1 ) ;
# else
2023-03-12 15:27:28 +00:00
this - > variable . Signal ( ) ;
2023-12-10 19:25:31 +00:00
# endif
2023-03-12 15:27:28 +00:00
return true ;
}
WaitBuffer WaitBuffer : : From ( const void * pBuf , AuUInt8 uSize )
{
WaitBuffer wait ;
AuMemcpy ( wait . buffer , pBuf , uSize ) ;
wait . uSize = uSize ;
return AuMove ( wait ) ;
}
2024-03-12 22:50:22 +00:00
bool WaitBuffer : : Compare ( const void * pHotAddress , AuUInt8 uSize , WaitState & state )
{
auto eMethod = state . eWaitMethod ;
return WaitBuffer : : Compare ( pHotAddress , uSize , state . compare . buffer , state . uDownsizeMask , eMethod ) ;
}
bool WaitBuffer : : Compare ( const void * pHotAddress , AuUInt8 uSize , const void * pCompare , AuUInt64 uMask , EWaitMethod eMethod )
2023-10-30 14:50:28 +00:00
{
2024-03-02 23:23:16 +00:00
bool bRet { } ;
2024-03-21 00:28:50 +00:00
AURORA_COMPILER_VOLATILE_BARRIER ( ) ;
2024-03-02 23:23:16 +00:00
2024-03-12 22:50:22 +00:00
#if 0
switch ( eMethod )
2023-10-30 14:50:28 +00:00
{
2024-03-12 22:50:22 +00:00
case EWaitMethod : : eEqual :
case EWaitMethod : : eNotEqual :
2023-10-30 14:50:28 +00:00
{
2024-03-12 22:50:22 +00:00
auto & uSrcWord = * AuReinterpretCast < const AuUInt32 * > ( pHotAddress ) ;
auto & uCmpWord = * AuReinterpretCast < const AuUInt32 * > ( pCompare ) ;
2024-03-02 23:23:16 +00:00
bRet = ( uSrcWord & uMask ) = = ( uCmpWord & uMask ) ;
2024-03-12 22:50:22 +00:00
bRet ^ = bool ( eMethod = = EWaitMethod : : eEqual ) ;
break ;
} ;
default :
{
DO_OF_METHOD_TYPE ( return , Compare2 , pHotAddress , uSize , pCompare )
2023-10-30 14:50:28 +00:00
}
2024-03-12 22:50:22 +00:00
}
# else
DO_OF_METHOD_TYPE ( return , Compare2 , pHotAddress , uSize , pCompare )
# endif
2024-03-02 23:23:16 +00:00
return bRet ;
2023-10-30 14:50:28 +00:00
}
2024-03-12 22:50:22 +00:00
template < EWaitMethod eMethod , bool bFast >
bool WaitBuffer : : Compare2 ( const void * pHot , AuUInt8 uSize , const void * pBuf2 , AuUInt64 uMask )
2023-10-30 14:50:28 +00:00
{
2024-06-19 21:05:17 +00:00
return Compare2 < eMethod , bFast > ( ( const volatile void * ) pHot , uSize , pBuf2 , uMask ) ;
}
template < EWaitMethod eMethod , bool bFast >
bool WaitBuffer : : Compare2 ( const volatile void * pHot , AuUInt8 uSize , const void * pBuf2 , AuUInt64 uMask )
{
# if !defined(AURORA_COMPILER_CLANG) && !defined(AURORA_COMPILER_MSVC)
2024-03-21 00:28:50 +00:00
AURORA_COMPILER_VOLATILE_BARRIER ( ) ;
2024-06-19 21:05:17 +00:00
# endif
2024-03-02 23:23:16 +00:00
2024-03-12 22:50:22 +00:00
if constexpr ( ! bFast )
2023-11-29 05:34:57 +00:00
{
2023-10-30 14:50:28 +00:00
2024-03-12 22:50:22 +00:00
if constexpr ( eMethod = = EWaitMethod : : eNotEqual )
{
switch ( uSize )
{
case 1 :
return ( AuReadU8 ( pHot , 0 ) & uMask ) = = ( AuReadU8 ( pBuf2 , 0 ) & uMask ) ;
case 2 :
return ( AuReadU16 ( pHot , 0 ) & uMask ) = = ( AuReadU16 ( pBuf2 , 0 ) & uMask ) ;
case 4 :
return ( AuReadU32 ( pHot , 0 ) & uMask ) = = ( AuReadU32 ( pBuf2 , 0 ) & uMask ) ;
case 8 :
return ( AuReadU64 ( pHot , 0 ) & uMask ) = = ( AuReadU64 ( pBuf2 , 0 ) & uMask ) ;
default :
2024-06-19 21:05:17 +00:00
return ( AuMemcmp ( ( const void * ) pHot , pBuf2 , uSize ) = = 0 ) ;
2024-03-12 22:50:22 +00:00
}
}
2023-03-12 15:27:28 +00:00
2024-03-12 22:50:22 +00:00
if constexpr ( eMethod = = EWaitMethod : : eEqual )
{
switch ( uSize )
{
case 1 :
return ! ( ( AuReadU8 ( pHot , 0 ) & uMask ) = = ( AuReadU8 ( pBuf2 , 0 ) & uMask ) ) ;
case 2 :
return ! ( ( AuReadU16 ( pHot , 0 ) & uMask ) = = ( AuReadU16 ( pBuf2 , 0 ) & uMask ) ) ;
case 4 :
return ! ( ( AuReadU32 ( pHot , 0 ) & uMask ) = = ( AuReadU32 ( pBuf2 , 0 ) & uMask ) ) ;
case 8 :
return ! ( ( AuReadU64 ( pHot , 0 ) & uMask ) = = ( AuReadU64 ( pBuf2 , 0 ) & uMask ) ) ;
default :
2024-06-19 21:05:17 +00:00
return ! ( AuMemcmp ( ( const void * ) pHot , pBuf2 , uSize ) = = 0 ) ;
2024-03-12 22:50:22 +00:00
}
}
if constexpr ( eMethod = = EWaitMethod : : eGreaterThanCompare )
{
switch ( uSize )
{
case 1 :
return ! ( ( AuReadU8 ( pHot , 0 ) & uMask ) > ( AuReadU8 ( pBuf2 , 0 ) & uMask ) ) ;
case 2 :
return ! ( ( AuReadU16 ( pHot , 0 ) & uMask ) > ( AuReadU16 ( pBuf2 , 0 ) & uMask ) ) ;
case 4 :
return ! ( ( AuReadU32 ( pHot , 0 ) & uMask ) > ( AuReadU32 ( pBuf2 , 0 ) & uMask ) ) ;
case 8 :
return ! ( ( AuReadU64 ( pHot , 0 ) & uMask ) > ( AuReadU64 ( pBuf2 , 0 ) & uMask ) ) ;
default :
return false ;
}
}
if constexpr ( eMethod = = EWaitMethod : : eGreaterThanOrEqualsCompare )
{
switch ( uSize )
{
case 1 :
return ! ( ( AuReadU8 ( pHot , 0 ) & uMask ) > = ( AuReadU8 ( pBuf2 , 0 ) & uMask ) ) ;
case 2 :
return ! ( ( AuReadU16 ( pHot , 0 ) & uMask ) > = ( AuReadU16 ( pBuf2 , 0 ) & uMask ) ) ;
case 4 :
return ! ( ( AuReadU32 ( pHot , 0 ) & uMask ) > = ( AuReadU32 ( pBuf2 , 0 ) & uMask ) ) ;
case 8 :
return ! ( ( AuReadU64 ( pHot , 0 ) & uMask ) > = ( AuReadU64 ( pBuf2 , 0 ) & uMask ) ) ;
default :
return false ;
}
}
if constexpr ( eMethod = = EWaitMethod : : eLessThanCompare )
{
switch ( uSize )
{
case 1 :
return ! ( ( AuReadU8 ( pHot , 0 ) & uMask ) < ( AuReadU8 ( pBuf2 , 0 ) & uMask ) ) ;
case 2 :
return ! ( ( AuReadU16 ( pHot , 0 ) & uMask ) < ( AuReadU16 ( pBuf2 , 0 ) & uMask ) ) ;
case 4 :
return ! ( ( AuReadU32 ( pHot , 0 ) & uMask ) < ( AuReadU32 ( pBuf2 , 0 ) & uMask ) ) ;
case 8 :
return ! ( ( AuReadU64 ( pHot , 0 ) & uMask ) < ( AuReadU64 ( pBuf2 , 0 ) & uMask ) ) ;
default :
return false ;
}
}
if constexpr ( eMethod = = EWaitMethod : : eLessThanOrEqualsCompare )
{
switch ( uSize )
{
case 1 :
return ! ( ( AuReadU8 ( pHot , 0 ) & uMask ) < = ( AuReadU8 ( pBuf2 , 0 ) & uMask ) ) ;
case 2 :
return ! ( ( AuReadU16 ( pHot , 0 ) & uMask ) < = ( AuReadU16 ( pBuf2 , 0 ) & uMask ) ) ;
case 4 :
return ! ( ( AuReadU32 ( pHot , 0 ) & uMask ) < = ( AuReadU32 ( pBuf2 , 0 ) & uMask ) ) ;
case 8 :
return ! ( ( AuReadU64 ( pHot , 0 ) & uMask ) < = ( AuReadU64 ( pBuf2 , 0 ) & uMask ) ) ;
default :
return false ;
}
}
2024-03-02 23:23:16 +00:00
2024-11-14 11:18:47 +00:00
if constexpr ( eMethod = = EWaitMethod : : eAnd )
{
switch ( uSize )
{
case 1 :
return ! ( ( AuReadU8 ( pHot , 0 ) & uMask ) & ( AuReadU8 ( pBuf2 , 0 ) & uMask ) ) ;
case 2 :
return ! ( ( AuReadU16 ( pHot , 0 ) & uMask ) & ( AuReadU16 ( pBuf2 , 0 ) & uMask ) ) ;
case 4 :
return ! ( ( AuReadU32 ( pHot , 0 ) & uMask ) & ( AuReadU32 ( pBuf2 , 0 ) & uMask ) ) ;
case 8 :
return ! ( ( AuReadU64 ( pHot , 0 ) & uMask ) & ( AuReadU64 ( pBuf2 , 0 ) & uMask ) ) ;
default :
return false ;
}
}
if constexpr ( eMethod = = EWaitMethod : : eNotAnd )
{
switch ( uSize )
{
case 1 :
return ( ( AuReadU8 ( pHot , 0 ) & uMask ) & ( AuReadU8 ( pBuf2 , 0 ) & uMask ) ) ;
case 2 :
return ( ( AuReadU16 ( pHot , 0 ) & uMask ) & ( AuReadU16 ( pBuf2 , 0 ) & uMask ) ) ;
case 4 :
return ( ( AuReadU32 ( pHot , 0 ) & uMask ) & ( AuReadU32 ( pBuf2 , 0 ) & uMask ) ) ;
case 8 :
return ( ( AuReadU64 ( pHot , 0 ) & uMask ) & ( AuReadU64 ( pBuf2 , 0 ) & uMask ) ) ;
default :
return false ;
}
}
2023-03-12 15:27:28 +00:00
}
else
{
2024-03-12 22:50:22 +00:00
if constexpr ( eMethod = = EWaitMethod : : eNotEqual )
{
switch ( uSize )
{
case 1 :
return ( AuReadU8 ( pHot , 0 ) ) = = ( AuReadU8 ( pBuf2 , 0 ) ) ;
case 2 :
return ( AuReadU16 ( pHot , 0 ) ) = = ( AuReadU16 ( pBuf2 , 0 ) ) ;
case 4 :
return ( AuReadU32 ( pHot , 0 ) ) = = ( AuReadU32 ( pBuf2 , 0 ) ) ;
case 8 :
return ( AuReadU64 ( pHot , 0 ) ) = = ( AuReadU64 ( pBuf2 , 0 ) ) ;
default :
2024-06-19 21:05:17 +00:00
return ( AuMemcmp ( ( const void * ) pHot , pBuf2 , uSize ) = = 0 ) ;
2024-03-12 22:50:22 +00:00
}
}
if constexpr ( eMethod = = EWaitMethod : : eEqual )
{
switch ( uSize )
{
case 1 :
return ! ( ( AuReadU8 ( pHot , 0 ) ) = = ( AuReadU8 ( pBuf2 , 0 ) ) ) ;
case 2 :
return ! ( ( AuReadU16 ( pHot , 0 ) ) = = ( AuReadU16 ( pBuf2 , 0 ) ) ) ;
case 4 :
return ! ( ( AuReadU32 ( pHot , 0 ) ) = = ( AuReadU32 ( pBuf2 , 0 ) ) ) ;
case 8 :
return ! ( ( AuReadU64 ( pHot , 0 ) ) = = ( AuReadU64 ( pBuf2 , 0 ) ) ) ;
default :
2024-06-19 21:05:17 +00:00
return ! ( AuMemcmp ( ( const void * ) pHot , pBuf2 , uSize ) = = 0 ) ;
2024-03-12 22:50:22 +00:00
}
}
if constexpr ( eMethod = = EWaitMethod : : eGreaterThanCompare )
{
switch ( uSize )
{
case 1 :
return ! ( ( AuReadU8 ( pHot , 0 ) ) > ( AuReadU8 ( pBuf2 , 0 ) ) ) ;
case 2 :
return ! ( ( AuReadU16 ( pHot , 0 ) ) > ( AuReadU16 ( pBuf2 , 0 ) ) ) ;
case 4 :
return ! ( ( AuReadU32 ( pHot , 0 ) ) > ( AuReadU32 ( pBuf2 , 0 ) ) ) ;
case 8 :
return ! ( ( AuReadU64 ( pHot , 0 ) ) > ( AuReadU64 ( pBuf2 , 0 ) ) ) ;
default :
return false ;
}
}
if constexpr ( eMethod = = EWaitMethod : : eGreaterThanOrEqualsCompare )
{
switch ( uSize )
{
case 1 :
return ! ( ( AuReadU8 ( pHot , 0 ) ) > = ( AuReadU8 ( pBuf2 , 0 ) ) ) ;
case 2 :
return ! ( ( AuReadU16 ( pHot , 0 ) ) > = ( AuReadU16 ( pBuf2 , 0 ) ) ) ;
case 4 :
return ! ( ( AuReadU32 ( pHot , 0 ) ) > = ( AuReadU32 ( pBuf2 , 0 ) ) ) ;
case 8 :
return ! ( ( AuReadU64 ( pHot , 0 ) ) > = ( AuReadU64 ( pBuf2 , 0 ) ) ) ;
default :
return false ;
}
}
if constexpr ( eMethod = = EWaitMethod : : eLessThanCompare )
{
switch ( uSize )
{
case 1 :
return ! ( ( AuReadU8 ( pHot , 0 ) ) < ( AuReadU8 ( pBuf2 , 0 ) ) ) ;
case 2 :
return ! ( ( AuReadU16 ( pHot , 0 ) ) < ( AuReadU16 ( pBuf2 , 0 ) ) ) ;
case 4 :
return ! ( ( AuReadU32 ( pHot , 0 ) ) < ( AuReadU32 ( pBuf2 , 0 ) ) ) ;
case 8 :
return ! ( ( AuReadU64 ( pHot , 0 ) ) < ( AuReadU64 ( pBuf2 , 0 ) ) ) ;
default :
return false ;
}
}
if constexpr ( eMethod = = EWaitMethod : : eLessThanOrEqualsCompare )
{
switch ( uSize )
{
case 1 :
return ! ( ( AuReadU8 ( pHot , 0 ) ) < = ( AuReadU8 ( pBuf2 , 0 ) ) ) ;
case 2 :
return ! ( ( AuReadU16 ( pHot , 0 ) ) < = ( AuReadU16 ( pBuf2 , 0 ) ) ) ;
case 4 :
return ! ( ( AuReadU32 ( pHot , 0 ) ) < = ( AuReadU32 ( pBuf2 , 0 ) ) ) ;
case 8 :
return ! ( ( AuReadU64 ( pHot , 0 ) ) < = ( AuReadU64 ( pBuf2 , 0 ) ) ) ;
default :
return false ;
}
}
2023-03-12 15:27:28 +00:00
2024-11-14 11:18:47 +00:00
if constexpr ( eMethod = = EWaitMethod : : eAnd )
{
switch ( uSize )
{
case 1 :
return ! ( AuReadU8 ( pHot , 0 ) & AuReadU8 ( pBuf2 , 0 ) ) ;
case 2 :
return ! ( AuReadU16 ( pHot , 0 ) & AuReadU16 ( pBuf2 , 0 ) ) ;
case 4 :
return ! ( AuReadU32 ( pHot , 0 ) & AuReadU32 ( pBuf2 , 0 ) ) ;
case 8 :
return ! ( AuReadU64 ( pHot , 0 ) & AuReadU64 ( pBuf2 , 0 ) ) ;
default :
return false ;
}
}
if constexpr ( eMethod = = EWaitMethod : : eNotAnd )
{
switch ( uSize )
{
case 1 :
return ( AuReadU8 ( pHot , 0 ) & AuReadU8 ( pBuf2 , 0 ) ) ;
case 2 :
return ( AuReadU16 ( pHot , 0 ) & AuReadU16 ( pBuf2 , 0 ) ) ;
case 4 :
return ( AuReadU32 ( pHot , 0 ) & AuReadU32 ( pBuf2 , 0 ) ) ;
case 8 :
return ( AuReadU64 ( pHot , 0 ) & AuReadU64 ( pBuf2 , 0 ) ) ;
default :
return false ;
}
}
2023-03-12 15:27:28 +00:00
}
2024-03-02 23:23:16 +00:00
2024-03-12 22:50:22 +00:00
return false ;
2023-03-12 15:27:28 +00:00
}
2024-03-12 22:50:22 +00:00
WaitEntry * ProcessWaitNodeContainer : : WaitBufferFrom ( const void * pAddress , AuUInt8 uSize , bool bScheduleFirst , const void * pCompareAddress , EWaitMethod eWaitMethod )
2023-03-12 15:27:28 +00:00
{
2023-07-05 17:25:07 +00:00
# if defined(HACK_NO_INVALID_ACCESS_LEAK_SHARED_REF_ON_DESTROYED_THREAD)
auto pReturn = tlsWaitEntry . get ( ) ;
# else
2023-06-11 18:13:37 +00:00
auto pReturn = & tlsWaitEntry ;
2023-07-05 17:25:07 +00:00
# endif
2024-03-02 23:23:16 +00:00
pReturn - > pAddress = pAddress ;
pReturn - > uSize = uSize ;
pReturn - > pCompareAddress = pCompareAddress ;
2024-03-12 22:50:22 +00:00
pReturn - > eWaitMethod = eWaitMethod ;
2023-03-12 15:27:28 +00:00
2023-12-11 18:22:38 +00:00
if ( bScheduleFirst /*First in, First Out*/ )
2023-03-12 15:27:28 +00:00
{
Lock ( ) ;
2023-12-11 20:29:45 +00:00
if ( ! pReturn - > bAlive )
2023-06-12 17:31:10 +00:00
{
2023-12-11 20:29:45 +00:00
pReturn - > bAlive = true ;
2023-12-11 18:22:38 +00:00
if ( auto pLoadFromMemory = this - > waitList . pHead )
{
pLoadFromMemory - > pBefore = pReturn ;
pReturn - > pNext = pLoadFromMemory ;
}
else
{
this - > waitList . pTail = pReturn ;
}
this - > waitList . pHead = pReturn ;
2023-06-12 17:31:10 +00:00
}
2023-12-11 18:22:38 +00:00
Unlock ( ) ;
}
else /*Last In, First Out*/
{
Lock ( ) ;
if ( ! pReturn - > bAlive )
2023-06-12 17:31:10 +00:00
{
2023-12-11 20:29:45 +00:00
pReturn - > bAlive = true ;
2023-12-11 18:22:38 +00:00
if ( auto pLoadFromMemory = this - > waitList . pTail )
{
pLoadFromMemory - > pNext = pReturn ;
pReturn - > pBefore = pLoadFromMemory ;
}
else
{
this - > waitList . pHead = pReturn ;
}
2023-06-12 17:31:10 +00:00
this - > waitList . pTail = pReturn ;
}
2023-03-12 15:27:28 +00:00
Unlock ( ) ;
}
2023-06-11 18:13:37 +00:00
return pReturn ;
2023-03-12 15:27:28 +00:00
}
2023-06-12 17:31:10 +00:00
template < typename T >
2023-07-30 08:34:39 +00:00
bool ProcessWaitNodeContainer : : IterateWake ( T callback )
2023-06-12 17:31:10 +00:00
{
bool bRetStatus { true } ;
2023-12-02 03:35:24 +00:00
if ( AuAtomicLoad ( ( AuUInt * ) & this - > waitList . pTail ) = = 0 )
{
return true ;
}
2023-06-12 17:31:10 +00:00
Lock ( ) ;
{
// FIFO
auto pCurrentHead = this - > waitList . pTail ;
while ( pCurrentHead )
{
2023-12-21 15:54:05 +00:00
decltype ( pCurrentHead ) pBefore { } ;
2024-11-23 20:01:22 +00:00
# if !defined(WOA_SEMAPHORE_MODE) && defined(WOA_STRICTER_FIFO)
// do { ... | bAlive consumer | } while (...) lock guard
AU_LOCK_GUARD ( pCurrentHead - > mutex ) ;
# elif !defined(WOA_SEMAPHORE_MODE) && !defined(WOA_STRICTER_FIFO)
// Condvar wait-list insertion barrier required for binary-semaphore-like conditions.
// We only need to lock against the { lock() if (should Sleep) { *** waitList++; *** unlock(); yield(); lock() } else { ... } unlocks() } condvar pattern.
// I often only care about the order of ->Signal() after the CondVar::waitList++ to ensure one state change is paired with one waitList signal.
// Don't block during the wakeup check, we only care about observing the condvar or semaphore waitlist, no codeguarding mutex required.
2023-12-05 07:15:54 +00:00
{
AU_LOCK_GUARD ( pCurrentHead - > mutex ) ;
}
2023-12-10 19:25:31 +00:00
# endif
2023-06-12 17:31:10 +00:00
2024-11-23 20:01:22 +00:00
AuAtomicStore < AuUInt8 > ( & pCurrentHead - > bAlive , 0 ) ;
2023-06-12 17:31:10 +00:00
auto [ bCont , bRemove ] = callback ( * pCurrentHead ) ;
2023-12-21 15:54:05 +00:00
pBefore = pCurrentHead - > pBefore ;
2023-06-12 17:31:10 +00:00
if ( bRemove )
{
2024-11-23 20:01:22 +00:00
this - > RemoveEntry < true > ( pCurrentHead ) ;
}
else
{
AuAtomicStore < AuUInt8 > ( & pCurrentHead - > bAlive , 1 ) ;
2023-06-12 17:31:10 +00:00
}
if ( ! bCont )
{
bRetStatus = false ;
break ;
}
2023-03-12 15:27:28 +00:00
2023-12-21 15:54:05 +00:00
if ( pBefore = = pCurrentHead )
2023-11-17 23:06:08 +00:00
{
break ;
}
2023-12-21 15:54:05 +00:00
pCurrentHead = pBefore ;
2023-06-12 17:31:10 +00:00
}
}
2023-03-12 15:27:28 +00:00
Unlock ( ) ;
return bRetStatus ;
}
2024-11-23 20:01:22 +00:00
template < bool bAllUnderLock >
void ProcessWaitNodeContainer : : RemoveEntry ( WaitEntry * pEntry )
2023-11-17 23:06:08 +00:00
{
2023-12-21 15:54:05 +00:00
if ( this - > waitList . pHead = = pEntry )
2023-11-17 23:06:08 +00:00
{
2023-12-21 15:54:05 +00:00
this - > waitList . pHead = pEntry - > pNext ;
}
2023-11-17 23:06:08 +00:00
2023-12-21 15:54:05 +00:00
if ( this - > waitList . pTail = = pEntry )
{
this - > waitList . pTail = pEntry - > pBefore ;
}
2023-11-17 23:06:08 +00:00
2024-06-19 21:05:17 +00:00
if ( auto pBefore = pEntry - > pBefore )
2023-12-21 15:54:05 +00:00
{
2024-06-19 21:05:17 +00:00
pBefore - > pNext = pEntry - > pNext ;
2023-12-21 15:54:05 +00:00
}
2023-11-17 23:06:08 +00:00
2024-06-19 21:05:17 +00:00
if ( auto pNext = pEntry - > pNext )
2023-12-21 15:54:05 +00:00
{
2024-06-19 21:05:17 +00:00
pNext - > pBefore = pEntry - > pBefore ;
2023-12-21 15:54:05 +00:00
}
2023-11-17 23:06:08 +00:00
2023-12-21 15:54:05 +00:00
if ( bAllUnderLock )
{
pEntry - > pBefore = nullptr ;
pEntry - > pNext = nullptr ;
2024-11-23 20:01:22 +00:00
//pEntry->bAlive = false; - redundant
2023-12-21 15:54:05 +00:00
}
}
2023-11-17 23:06:08 +00:00
2023-12-21 15:54:05 +00:00
void ProcessWaitNodeContainer : : RemoveSelf ( WaitEntry * pSelf )
{
{
this - > Lock ( ) ;
2024-11-23 20:01:22 +00:00
this - > RemoveEntry < false > ( pSelf ) ;
2023-12-21 15:54:05 +00:00
this - > Unlock ( ) ;
2023-11-17 23:06:08 +00:00
}
2023-12-21 15:54:05 +00:00
pSelf - > pBefore = nullptr ;
pSelf - > pNext = nullptr ;
pSelf - > bAlive = false ;
2023-11-17 23:06:08 +00:00
}
2023-07-30 08:34:39 +00:00
void ProcessWaitNodeContainer : : Lock ( )
2023-03-12 15:27:28 +00:00
{
2023-06-11 18:13:37 +00:00
DoSpinLockOnVar ( & this - > uAtomic ) ;
2023-03-12 15:27:28 +00:00
}
2023-07-30 08:34:39 +00:00
void ProcessWaitNodeContainer : : Unlock ( )
2023-03-12 15:27:28 +00:00
{
2024-06-23 03:08:58 +00:00
AuAtomicClearU8Lock ( & this - > uAtomic ) ;
2023-03-12 15:27:28 +00:00
}
2023-07-30 08:34:39 +00:00
2023-12-01 01:44:26 +00:00
# define AddressToIndex AuHashCode(pAddress) & (AuArraySize(this->list) - 1)
2023-12-01 01:35:10 +00:00
2024-03-12 22:50:22 +00:00
WaitEntry * ProcessWaitContainer : : WaitBufferFrom ( const void * pAddress , AuUInt8 uSize , bool bScheduleFirst , const void * pCompareAddress , EWaitMethod eWaitMethod )
2023-07-30 08:34:39 +00:00
{
2024-03-12 22:50:22 +00:00
return this - > list [ AddressToIndex ] . WaitBufferFrom ( pAddress , uSize , bScheduleFirst , pCompareAddress , eWaitMethod ) ;
2023-07-30 08:34:39 +00:00
}
template < typename T >
2023-08-19 19:37:24 +00:00
bool ProcessWaitContainer : : IterateWake ( const void * pAddress , T callback )
2023-07-30 08:34:39 +00:00
{
2023-12-01 01:35:10 +00:00
return this - > list [ AddressToIndex ] . IterateWake ( callback ) ;
2023-07-30 08:34:39 +00:00
}
2023-11-17 23:06:08 +00:00
void ProcessWaitContainer : : RemoveSelf ( const void * pAddress , WaitEntry * pSelf )
{
2023-12-01 01:35:10 +00:00
return this - > list [ AddressToIndex ] . RemoveSelf ( pSelf ) ;
2023-11-17 23:06:08 +00:00
}
2023-09-20 16:46:48 +00:00
bool IsNativeWaitOnSupported ( )
2023-03-12 15:27:28 +00:00
{
# if defined(AURORA_IS_MODERNNT_DERIVED)
2023-09-20 16:46:48 +00:00
return pWaitOnAddress & &
AuSwInfo : : IsWindows8Point1OrGreater ( ) ;
# elif defined(AURORA_PLATFORM_LINUX)
return true ;
# else
2024-03-03 00:25:10 +00:00
return SysNativeWaitOnAddressFutexSupported ( ) ;
2023-09-20 16:46:48 +00:00
# endif
}
2024-03-12 23:32:32 +00:00
AUKN_SYM bool IsWaitOnRecommended ( )
2023-09-20 16:46:48 +00:00
{
2023-12-21 15:54:05 +00:00
# if defined(WOA_ALWAYS_DUMB_OS_TARGET)
return false ;
# endif
2024-11-21 17:17:09 +00:00
# if defined(WOA_STRICTER_FIFO)
return false ;
# endif
2023-08-19 17:49:16 +00:00
static AuOptionalEx < bool > gIsWaitOnRecommendedCache { } ;
if ( gIsWaitOnRecommendedCache )
{
return gIsWaitOnRecommendedCache . value ( ) ;
}
2023-09-20 16:46:48 +00:00
if ( Primitives : : ThrdCfg : : gPreferEmulatedWakeOnAddress )
{
return false ;
}
bool bState = IsNativeWaitOnSupported ( ) ;
2023-08-19 17:49:16 +00:00
gIsWaitOnRecommendedCache = bState ;
return bState ;
2023-03-12 15:27:28 +00:00
}
/// @deprecated
AUKN_SYM const AuList < AuUInt8 > & GetValidWordSizes ( )
{
static const AuList < AuUInt8 > kArray =
# if defined(AURORA_IS_MODERNNT_DERIVED)
{ 1 , 2 , 4 , 8 } ;
# else
{ 4 } ;
# endif
return kArray ;
}
2024-03-12 22:50:22 +00:00
template < EWaitMethod T >
2023-08-22 10:08:56 +00:00
bool WaitOnAddressWide ( const void * pTargetAddress ,
2023-08-19 18:48:24 +00:00
const void * pCompareAddress ,
2023-03-12 15:27:28 +00:00
AuUInt8 uWordSize ,
AuOptional < AuUInt64 > qwNanoseconds ,
2023-06-15 19:44:27 +00:00
AuOptional < AuUInt64 > qwNanosecondsAbs ,
2024-03-02 23:23:16 +00:00
bool bOSSupportsWait ,
2024-03-12 22:50:22 +00:00
const void * pCompareAddress2 )
2023-03-12 15:27:28 +00:00
{
WaitState state ;
2024-03-02 23:23:16 +00:00
2023-10-30 14:50:28 +00:00
SysAssertDbg ( uWordSize < = 32 ) ;
2024-03-02 23:23:16 +00:00
2024-03-12 22:50:22 +00:00
auto pWaitEntry = gProcessWaitables . WaitBufferFrom ( pTargetAddress , uWordSize , true , pCompareAddress2 , T ) ;
2024-03-02 23:23:16 +00:00
// Unlocked update to a safer comparison address; hardens against bad code
{
state . compare = WaitBuffer : : From ( pCompareAddress , uWordSize ) ;
// Replace from pCompareAddress2 to our own memory to harden against bad volatile comparison pointers
pWaitEntry - > pCompareAddress = state . pCompare2 =
pCompareAddress2 ? state . compare . buffer : nullptr ;
}
2023-06-15 19:44:27 +00:00
if ( qwNanoseconds )
{
state . qwNanosecondsAbs = AuTime : : SteadyClockNS ( ) + qwNanoseconds . value ( ) ;
}
else if ( qwNanosecondsAbs )
{
state . qwNanosecondsAbs = qwNanosecondsAbs . value ( ) ;
}
2023-07-05 17:25:07 +00:00
# if defined(HACK_NO_INVALID_ACCESS_LEAK_SHARED_REF_ON_DESTROYED_THREAD)
auto pTempHoldMe = tlsWaitEntry ;
# endif
2024-03-12 22:50:22 +00:00
auto bResult = pWaitEntry - > SleepOn < T > ( state ) ;
2023-07-05 17:25:07 +00:00
# if defined(HACK_NO_INVALID_ACCESS_LEAK_SHARED_REF_ON_DESTROYED_THREAD)
pTempHoldMe . reset ( ) ;
# endif
2023-11-17 23:06:08 +00:00
if ( ! bResult )
{
gProcessWaitables . RemoveSelf ( pTargetAddress , pWaitEntry ) ;
}
2023-03-12 15:27:28 +00:00
return bResult ;
}
2024-03-12 22:50:22 +00:00
AuTuple < const void * , AuUInt8 , AuUInt64 > DecodeAddress ( const void * pAddress ,
AuUInt32 uWordSize )
2023-03-12 15:27:28 +00:00
{
# if defined(AURORA_IS_MODERNNT_DERIVED)
2024-03-12 22:50:22 +00:00
return AuMakeTuple ( pAddress , 0 , kMax64 ) ;
2023-03-12 15:27:28 +00:00
# endif
2023-09-09 14:11:33 +00:00
auto pRounded = AuPageRound ( AuUInt ( pAddress ) , AuUInt ( 4 ) ) ;
auto uDelta = ( AuUInt ) pAddress - pRounded ;
2023-04-16 22:58:27 +00:00
if ( uWordSize = = 8 )
{
2024-03-12 22:50:22 +00:00
return AuMakeTuple ( ( const void * ) pRounded , uDelta , kMax64 ) ;
2023-04-16 22:58:27 +00:00
}
2023-09-09 14:11:33 +00:00
AuUInt32 uSizeMask = ( 1ull < < ( uWordSize * 8 ) ) - 1ull ;
2023-04-16 22:58:27 +00:00
2023-03-12 15:27:28 +00:00
switch ( uDelta )
{
case 0 :
return AuMakeTuple ( pAddress , 0 , 0xFFFFFFFF & ( uSizeMask < < 0 ) ) ;
case 1 :
return AuMakeTuple ( pAddress , 1 , 0xFFFFFF00 & ( uSizeMask < < 8 ) ) ;
case 2 :
return AuMakeTuple ( pAddress , 2 , 0xFFFF0000 & ( uSizeMask < < 16 ) ) ;
case 3 :
return AuMakeTuple ( pAddress , 3 , 0xFF000000 & ( uSizeMask < < 24 ) ) ;
default :
SysPanic ( " Invalid Branch " ) ;
}
}
static bool RunOSWaitOnAddressTimed ( const void * pTargetAddress ,
const void * pCompareAddress ,
AuUInt8 uWordSize ,
2023-06-15 19:44:27 +00:00
AuUInt64 uAbsTimeSteadyClock ,
AuUInt64 uRelativeNanoseconds ,
2023-10-30 14:50:28 +00:00
AuOptional < AuUInt64 > uAbsTimeAltClock /* hint */ ,
bool bSpun = false )
2023-03-12 15:27:28 +00:00
{
# if defined(AURORA_IS_MODERNNT_DERIVED)
2023-06-15 19:44:27 +00:00
if ( pRtlWaitOnAddress )
2023-03-12 15:27:28 +00:00
{
2023-06-15 19:44:27 +00:00
AuUInt64 uNow { } ;
while ( uAbsTimeSteadyClock ?
( uAbsTimeSteadyClock > ( uNow = AuTime : : SteadyClockNS ( ) ) ) :
true )
2023-03-12 15:27:28 +00:00
{
2023-06-15 19:44:27 +00:00
LARGE_INTEGER word { } ;
if ( uAbsTimeAltClock )
{
word . QuadPart = AuTime : : ConvertTimestampNs ( uAbsTimeAltClock . value ( ) ) ;
}
else if ( uAbsTimeSteadyClock )
{
if ( uAbsTimeSteadyClock < = uNow )
{
2024-03-12 22:50:22 +00:00
return ! WaitBuffer : : Compare2 < EWaitMethod : : eNotEqual , true > ( pTargetAddress , uWordSize , pCompareAddress ) ;
2023-06-15 19:44:27 +00:00
}
word . QuadPart = - ( AuInt64 ( uAbsTimeSteadyClock - uNow ) / 100ull ) ;
2023-06-15 20:15:58 +00:00
if ( ! word . QuadPart )
{
word . QuadPart = 1 ;
}
2023-06-15 19:44:27 +00:00
}
2023-06-15 23:10:53 +00:00
2024-03-12 22:50:22 +00:00
if ( WaitBuffer : : Compare2 < EWaitMethod : : eNotEqual , true > ( pTargetAddress , uWordSize , pCompareAddress ) )
2023-03-12 15:27:28 +00:00
{
2024-03-12 22:50:22 +00:00
if ( pRtlWaitOnAddress ( pTargetAddress , pCompareAddress , uWordSize , & word ) )
2023-06-15 19:44:27 +00:00
{
return true ;
}
else if ( ! uAbsTimeSteadyClock )
{
return false ;
}
}
else
{
return true ;
2023-03-12 15:27:28 +00:00
}
}
2023-06-15 19:44:27 +00:00
return false ;
2023-03-12 15:27:28 +00:00
}
else
{
2023-06-15 19:44:27 +00:00
// ~~some paths might miss the uRelativeNanoseconds, like cas loops.~~
// most paths will now skimp on the relative values
if ( uAbsTimeSteadyClock & & ! uRelativeNanoseconds )
2023-03-13 23:57:32 +00:00
{
2023-06-15 19:44:27 +00:00
AuInt64 iDelta = uAbsTimeSteadyClock ;
iDelta - = AuTime : : SteadyClockNS ( ) ;
if ( iDelta < = 0 )
{
2024-03-12 22:50:22 +00:00
return ! WaitBuffer : : Compare2 < EWaitMethod : : eNotEqual , true > ( pTargetAddress , uWordSize , pCompareAddress ) ;
2023-06-15 19:44:27 +00:00
}
uRelativeNanoseconds = iDelta ;
2023-03-13 23:57:32 +00:00
}
2023-08-22 08:55:05 +00:00
auto uMaxSwitches = gRuntimeConfig . threadingConfig . uUWPNanosecondEmulationMaxYields ;
2023-09-09 16:37:14 +00:00
auto bUWPNanosecondEmulationCheckFirst = Primitives : : ThrdCfg : : gUWPNanosecondEmulationCheckFirst ;
2023-08-22 08:55:05 +00:00
2023-06-15 19:44:27 +00:00
// LockN(<1MS) on a platform without that resolution of yielding... damn
auto uMS = AuNSToMS < AuUInt32 > ( uRelativeNanoseconds ) ;
if ( ! uMS )
2023-03-13 23:57:32 +00:00
{
2023-06-15 19:44:27 +00:00
// first: cpu spin to avoid the kernel all together
2023-10-30 14:50:28 +00:00
if ( ! bSpun )
2023-03-13 23:57:32 +00:00
{
2023-10-30 14:50:28 +00:00
if ( TryWaitOnAddress ( ( void * ) pTargetAddress , ( void * ) pCompareAddress , uWordSize ) )
{
return true ;
}
2023-03-13 23:57:32 +00:00
}
2023-06-15 19:44:27 +00:00
// second: yield
2023-08-22 08:55:05 +00:00
unsigned uLimit { } ;
2023-06-15 19:44:27 +00:00
do
2023-03-13 23:57:32 +00:00
{
2024-03-12 22:50:22 +00:00
if ( ! WaitBuffer : : Compare2 < EWaitMethod : : eNotEqual , true > ( pTargetAddress , uWordSize , pCompareAddress ) )
2023-06-15 19:44:27 +00:00
{
break ;
}
2023-03-13 23:57:32 +00:00
AuThreading : : ContextYield ( ) ;
2023-08-22 08:55:05 +00:00
if ( bUWPNanosecondEmulationCheckFirst )
{
if ( uLimit + + > uMaxSwitches )
{
break ;
}
}
2023-03-13 23:57:32 +00:00
}
2023-06-15 19:44:27 +00:00
while ( uAbsTimeSteadyClock > AuTime : : SteadyClockNS ( ) ) ; // ...until times up
}
else // high level lock function was called with ms scale resolution
{
// first: wait on the address with an ms scale timeout
( void ) pWaitOnAddress ( ( void * ) pTargetAddress , ( void * ) pCompareAddress , uWordSize , uMS ) ;
2023-10-30 14:50:28 +00:00
// take a copy
auto expect = WaitBuffer : : From ( pCompareAddress , uWordSize ) ;
2023-06-15 19:44:27 +00:00
// never trust the error value/status provided by wait addresses - instead, do a quick compare
2024-03-12 22:50:22 +00:00
if ( ! WaitBuffer : : Compare2 < EWaitMethod : : eNotEqual , true > ( pTargetAddress , uWordSize , pCompareAddress ) )
2023-03-13 23:57:32 +00:00
{
2023-06-15 19:44:27 +00:00
// best case: we woke up during the ms-res waitonaddress
return true ;
}
// attempt to yield again, potentially context switching a few times to hit any NS remainder
AuUInt64 uNow { } ;
unsigned uLimit { } ;
while ( uAbsTimeSteadyClock > ( uNow = AuTime : : SteadyClockNS ( ) ) )
{
uMS = AuNSToMS < AuUInt32 > ( uAbsTimeSteadyClock - uNow ) ;
2024-05-03 11:14:52 +00:00
if ( Primitives : : DoTryIfAlderLake ( [ & ] ( )
2023-06-15 19:44:27 +00:00
{
2024-03-12 22:50:22 +00:00
return ! WaitBuffer : : Compare2 < EWaitMethod : : eNotEqual , true > ( pTargetAddress , uWordSize , pCompareAddress ) ;
2024-05-03 11:14:52 +00:00
} , pTargetAddress ) )
2023-06-15 19:44:27 +00:00
{
// hit it within the span of 1 << SpinLoopPowerA SMT stalls
return true ;
}
if ( ! uMS )
{
// burn off any remainder cycles by switching contexts (this isnt a very long time usually)
2023-08-22 08:55:05 +00:00
if ( uLimit + + < uMaxSwitches )
2023-06-15 19:44:27 +00:00
{
AuThreading : : ContextYield ( ) ;
}
else
{
// do not burn the cpu to meet the timeout. we'll just undershoot.
return false ;
}
}
else
{
( void ) pWaitOnAddress ( ( void * ) pTargetAddress , ( void * ) pCompareAddress , uWordSize , uMS ) ;
}
2023-03-13 23:57:32 +00:00
}
}
2023-03-12 15:27:28 +00:00
}
2024-03-12 22:50:22 +00:00
return ! WaitBuffer : : Compare2 < EWaitMethod : : eNotEqual , true > ( pTargetAddress , uWordSize , pCompareAddress ) ;
2023-03-12 15:27:28 +00:00
2024-03-03 00:25:10 +00:00
# else
2023-03-12 15:27:28 +00:00
2024-03-03 00:25:10 +00:00
return SysWaitOnAddressTimed ( pTargetAddress ,
pCompareAddress ,
uWordSize ,
uAbsTimeSteadyClock ,
uRelativeNanoseconds ,
uAbsTimeAltClock ,
bSpun ) ;
2023-03-12 15:27:28 +00:00
# endif
}
static void RunOSWaitOnAddressNoTimedNoErrors ( const void * pTargetAddress ,
const void * pCompareAddress ,
2023-03-13 23:57:32 +00:00
WaitState & state )
2023-03-12 15:27:28 +00:00
{
2024-04-28 13:13:09 +00:00
while ( WaitBuffer : : Compare2 < EWaitMethod : : eNotEqual , kPlatformFutexNoForcedAlignedU32 > ( pTargetAddress , state . uWordSize , pCompareAddress , state . uDownsizeMask ) )
2023-03-12 15:27:28 +00:00
{
2024-03-03 00:25:10 +00:00
if ( ! SysWaitOnAddressNoTimed ( pTargetAddress , pCompareAddress , state . uWordSize ) )
2023-03-12 15:27:28 +00:00
{
2024-03-12 22:50:22 +00:00
//AuThreading::ContextYield();
2023-03-12 15:27:28 +00:00
}
}
}
2023-06-15 19:44:27 +00:00
static bool RunOSWaitOnAddressTimedSteady ( const void * pTargetAddress ,
2023-10-30 14:50:28 +00:00
const void * pCompareAddress ,
WaitState & state ,
bool bSpun = false )
2023-03-12 15:27:28 +00:00
{
2024-03-12 22:50:22 +00:00
# if 1
2024-04-28 13:13:09 +00:00
if ( ! WaitBuffer : : Compare2 < EWaitMethod : : eNotEqual , kPlatformFutexNoForcedAlignedU32 > ( pTargetAddress , state . uWordSize , pCompareAddress , state . uDownsizeMask ) )
2023-03-12 15:27:28 +00:00
{
return true ;
}
2023-10-30 14:50:28 +00:00
( void ) RunOSWaitOnAddressTimed ( pTargetAddress , pCompareAddress , state . uWordSize , state . qwNanosecondsAbs . value ( ) , { } , { } , bSpun ) ;
2024-04-28 13:13:09 +00:00
return ! WaitBuffer : : Compare2 < EWaitMethod : : eNotEqual , kPlatformFutexNoForcedAlignedU32 > ( pTargetAddress , state . uWordSize , pCompareAddress , state . uDownsizeMask ) ;
2024-03-12 22:50:22 +00:00
# else
return RunOSWaitOnAddressTimed ( pTargetAddress , pCompareAddress , state . uWordSize , state . qwNanosecondsAbs . value ( ) , { } , { } , bSpun ) ;
# endif
2023-03-12 15:27:28 +00:00
}
2024-03-12 22:50:22 +00:00
template < EWaitMethod T >
2024-03-02 23:23:16 +00:00
static void RunOSWaitOnAddressEQNoTimedNoErrors ( const void * pTargetAddress ,
const void * pCompareAddress ,
WaitState & state )
{
while ( true )
{
WaitBuffer wb = WaitBuffer : : From ( pTargetAddress , state . uWordSize ) ;
2024-04-28 13:13:09 +00:00
if ( ! WaitBuffer : : Compare2 < T , kPlatformFutexNoForcedAlignedU32 > ( wb . buffer , state . uWordSize , pCompareAddress , state . uDownsizeMask ) )
2024-03-02 23:23:16 +00:00
{
return ;
}
2024-03-03 00:25:10 +00:00
( void ) SysWaitOnAddressNoTimed ( pTargetAddress , wb . buffer , state . uWordSize ) ;
2024-03-02 23:23:16 +00:00
2024-04-28 13:13:09 +00:00
if ( WaitBuffer : : Compare2 < T , kPlatformFutexNoForcedAlignedU32 > ( pTargetAddress , state . uWordSize , pCompareAddress , state . uDownsizeMask ) )
2024-03-02 23:23:16 +00:00
{
2024-03-12 22:50:22 +00:00
SysWakeOneOnAddress ( pTargetAddress ) ;
2024-03-02 23:23:16 +00:00
}
else
{
return ;
}
}
}
2024-03-12 22:50:22 +00:00
template < EWaitMethod T >
2024-03-02 23:23:16 +00:00
static bool RunOSWaitOnAddressEQTimedSteady ( const void * pTargetAddress ,
const void * pCompareAddress ,
WaitState & state ,
bool bSpun = false )
{
while ( true )
{
WaitBuffer wb = WaitBuffer : : From ( pTargetAddress , state . uWordSize ) ;
2024-04-28 13:13:09 +00:00
if ( ! WaitBuffer : : Compare2 < T , kPlatformFutexNoForcedAlignedU32 > ( wb . buffer , state . uWordSize , pCompareAddress , state . uDownsizeMask ) )
2024-03-02 23:23:16 +00:00
{
return true ;
}
bool bResult = RunOSWaitOnAddressTimed ( pTargetAddress , wb . buffer , state . uWordSize , state . qwNanosecondsAbs . value ( ) , { } , { } , bSpun ) ;
2024-04-28 13:13:09 +00:00
if ( WaitBuffer : : Compare2 < T , kPlatformFutexNoForcedAlignedU32 > ( pTargetAddress , state . uWordSize , pCompareAddress , state . uDownsizeMask ) )
2024-03-02 23:23:16 +00:00
{
2024-03-12 22:50:22 +00:00
SysWakeOneOnAddress ( pTargetAddress ) ;
2024-03-02 23:23:16 +00:00
if ( ! bResult )
{
return false ;
}
}
else
{
return true ;
}
}
}
2023-06-15 19:44:27 +00:00
// Windows 8+ thread primitives might use me instead of the public API
// it does work on Linux and Windows 8+
// it does not, however, work on emulated platforms
// this is intentional
2023-09-09 11:39:47 +00:00
bool InternalLTSWaitOnAddressHighRes ( const void * pTargetAddress ,
2023-09-02 03:55:43 +00:00
const void * pCompareAddress ,
2023-06-15 19:44:27 +00:00
AuUInt8 uWordSize ,
AuUInt64 qwNanosecondsAbs )
{
auto [ pWaitAddress , uDelta , uMask ] = DecodeAddress ( pTargetAddress , uWordSize ) ;
2023-08-19 18:48:24 +00:00
auto pCompareAddress2 = AuReinterpretCast < const char * > ( pCompareAddress ) - uDelta ;
2023-06-15 19:44:27 +00:00
WaitState state ;
state . uDownsizeMask = uMask ;
2024-03-12 22:50:22 +00:00
state . compare = uMask ! = kMax64 ?
2023-06-15 19:44:27 +00:00
WaitBuffer : : From ( pCompareAddress2 , 4 ) :
WaitBuffer : : From ( pCompareAddress2 , uWordSize ) ;
2024-03-12 22:50:22 +00:00
state . uWordSize = uMask ! = kMax64 ? 4 : uWordSize ;
2023-06-15 19:44:27 +00:00
if ( ! qwNanosecondsAbs )
{
RunOSWaitOnAddressNoTimedNoErrors ( pWaitAddress , pCompareAddress2 , state ) ;
return true ;
}
else
{
state . qwNanosecondsAbs = qwNanosecondsAbs ;
2023-10-30 14:50:28 +00:00
return RunOSWaitOnAddressTimedSteady ( pWaitAddress , pCompareAddress2 , state , true ) ;
2023-06-15 19:44:27 +00:00
}
}
2023-09-09 11:29:43 +00:00
void InternalLTSWakeAll ( const void * pTargetAddress )
{
2023-12-21 15:54:05 +00:00
# if defined(WOA_ALWAYS_DUMB_OS_TARGET)
WakeAllOnAddress ( pTargetAddress ) ;
# else
2023-09-09 11:29:43 +00:00
auto [ pWakeAddress , uDelta , uMask ] = DecodeAddress ( pTargetAddress , 1 ) ;
2024-03-03 00:25:10 +00:00
SysWakeAllOnAddress ( pWakeAddress ) ;
2023-12-21 15:54:05 +00:00
# endif
2023-09-09 11:29:43 +00:00
}
void InternalLTSWakeOne ( const void * pTargetAddress )
{
2023-12-21 15:54:05 +00:00
# if defined(WOA_ALWAYS_DUMB_OS_TARGET)
WakeOnAddress ( pTargetAddress ) ;
# else
2023-09-09 11:29:43 +00:00
auto [ pWakeAddress , uDelta , uMask ] = DecodeAddress ( pTargetAddress , 1 ) ;
2024-03-03 00:25:10 +00:00
if ( uDelta )
{
SysWakeAllOnAddress ( pWakeAddress ) ;
}
else
{
SysWakeNOnAddress ( pWakeAddress , 1 ) ;
}
2023-12-21 15:54:05 +00:00
# endif
2023-09-09 11:29:43 +00:00
}
2023-09-09 11:39:47 +00:00
void InternalLTSWakeCount ( const void * pTargetAddress , AuUInt32 uCount )
{
2023-12-21 15:54:05 +00:00
# if defined(WOA_ALWAYS_DUMB_OS_TARGET)
WakeNOnAddress ( pTargetAddress , uCount ) ;
# else
2023-09-09 11:39:47 +00:00
auto [ pWakeAddress , uDelta , uMask ] = DecodeAddress ( pTargetAddress , 1 ) ;
2024-03-03 00:25:10 +00:00
if ( uDelta )
{
SysWakeAllOnAddress ( pWakeAddress ) ;
}
else
{
SysWakeNOnAddress ( pWakeAddress , uCount ) ;
}
2023-12-21 15:54:05 +00:00
# endif
2023-09-09 11:39:47 +00:00
}
2024-03-12 22:50:22 +00:00
WOAFASTPUB bool WaitOnAddress ( const void * pTargetAddress ,
const void * pCompareAddress ,
AuUInt8 uWordSize ,
AuUInt64 qwNanoseconds ,
AuOptional < bool > optAlreadySpun )
2023-03-12 15:27:28 +00:00
{
2024-11-21 17:17:09 +00:00
# if !defined(WOA_STRICTER_FIFO)
2023-10-30 14:50:28 +00:00
// Avoid SteadyTime syscall in the event of HAL retardation (missing KUSER QPC, Linux vDSO, etc)
2024-03-12 22:50:22 +00:00
if ( ! WaitBuffer : : Compare2 < EWaitMethod : : eNotEqual , true > ( pTargetAddress , uWordSize , pCompareAddress , kMax64 ) )
2023-03-12 15:27:28 +00:00
{
2023-10-30 14:50:28 +00:00
return true ;
2023-03-12 15:27:28 +00:00
}
2024-11-21 17:17:09 +00:00
# endif
2023-03-12 15:27:28 +00:00
2023-10-30 14:50:28 +00:00
return WaitOnAddressSteady ( pTargetAddress ,
pCompareAddress ,
uWordSize ,
qwNanoseconds ? qwNanoseconds + AuTime : : SteadyClockNS ( ) : 0 ,
optAlreadySpun ) ;
2023-03-12 15:27:28 +00:00
}
2024-03-12 22:50:22 +00:00
WOAFASTPUB bool WaitOnAddressSpecial ( EWaitMethod eMethod ,
const void * pTargetAddress ,
const void * pCompareAddress ,
AuUInt8 uWordSize ,
AuUInt64 qwNanoseconds ,
AuOptional < bool > optAlreadySpun )
2024-03-02 23:23:16 +00:00
{
2024-11-21 17:17:09 +00:00
# if !defined(WOA_STRICTER_FIFO)
2024-03-02 23:23:16 +00:00
// Avoid SteadyTime syscall in the event of HAL retardation (missing KUSER QPC, Linux vDSO, etc)
2024-03-12 22:50:22 +00:00
if ( ! WaitBuffer : : Compare ( pTargetAddress , uWordSize , pCompareAddress , kMax64 , eMethod ) )
2024-03-02 23:23:16 +00:00
{
return true ;
}
2024-11-21 17:17:09 +00:00
# endif
2024-03-02 23:23:16 +00:00
2024-03-12 22:50:22 +00:00
return WaitOnAddressSpecialSteady ( eMethod ,
pTargetAddress ,
pCompareAddress ,
uWordSize ,
qwNanoseconds ? qwNanoseconds + AuTime : : SteadyClockNS ( ) : 0 ,
optAlreadySpun ) ;
2024-03-02 23:23:16 +00:00
}
2024-03-12 22:50:22 +00:00
template < EWaitMethod T >
auline bool TryWaitOnAddressSpecialTmpl ( const void * pTargetAddress ,
const void * pCompareAddress ,
AuUInt8 uWordSize )
2023-03-12 15:27:28 +00:00
{
2024-11-21 17:17:09 +00:00
# if !defined(WOA_STRICTER_FIFO)
2024-05-03 11:14:52 +00:00
return Primitives : : DoTryIfAlderLake ( [ & ] ( )
2023-03-13 23:57:32 +00:00
{
2024-03-12 22:50:22 +00:00
return ! WaitBuffer : : Compare2 < T , true > ( pTargetAddress , uWordSize , pCompareAddress ) ;
2024-05-03 11:14:52 +00:00
} , pTargetAddress ) ;
2024-11-21 17:17:09 +00:00
# else
return false ;
# endif
2023-11-14 14:44:56 +00:00
}
2024-03-12 22:50:22 +00:00
WOAFASTPUB bool TryWaitOnAddress ( const void * pTargetAddress ,
const void * pCompareAddress ,
AuUInt8 uWordSize )
2024-03-02 23:23:16 +00:00
{
2024-03-12 22:50:22 +00:00
return TryWaitOnAddressSpecialTmpl < EWaitMethod : : eNotEqual > ( pTargetAddress , pCompareAddress , uWordSize ) ;
2024-03-02 23:23:16 +00:00
}
2024-03-12 22:50:22 +00:00
WOAFASTPUB bool TryWaitOnAddressSpecial ( EWaitMethod eMethod ,
const void * pTargetAddress ,
const void * pCompareAddress ,
AuUInt8 uWordSize )
{
2024-11-21 17:17:09 +00:00
# if !defined(WOA_STRICTER_FIFO)
2024-03-12 22:50:22 +00:00
DO_OF_METHOD_TYPE ( return , TryWaitOnAddressSpecialTmpl , pTargetAddress , pCompareAddress , uWordSize ) ;
2024-11-21 17:17:09 +00:00
# endif
2024-03-12 22:50:22 +00:00
return false ;
}
WOAFASTPUB bool TryWaitOnAddressEx ( const void * pTargetAddress ,
const void * pCompareAddress ,
AuUInt8 uWordSize ,
const AuFunction < bool ( const void * , const void * , AuUInt8 ) > & check )
2023-11-14 14:44:56 +00:00
{
if ( ! check )
{
return TryWaitOnAddress ( pTargetAddress , pCompareAddress , uWordSize ) ;
}
2024-05-03 11:14:52 +00:00
return Primitives : : DoTryIfAlderLake ( [ & ] ( )
2023-11-14 14:44:56 +00:00
{
2024-03-12 22:50:22 +00:00
if ( WaitBuffer : : Compare2 < EWaitMethod : : eNotEqual , true > ( pTargetAddress , uWordSize , pCompareAddress ) )
2023-11-14 14:44:56 +00:00
{
return false ;
}
return check ( pTargetAddress , pCompareAddress , uWordSize ) ;
2024-05-03 11:14:52 +00:00
} , pTargetAddress ) ;
2023-03-12 15:27:28 +00:00
}
2024-03-12 22:50:22 +00:00
template < EWaitMethod T >
bool TryWaitOnAddressSpecialExTmpl ( const void * pTargetAddress ,
const void * pCompareAddress ,
AuUInt8 uWordSize ,
const AuFunction < bool ( const void * , const void * , AuUInt8 ) > & check )
2024-03-02 23:23:16 +00:00
{
2024-11-21 17:17:09 +00:00
# if !defined(WOA_STRICTER_FIFO)
2024-05-03 11:14:52 +00:00
return Primitives : : DoTryIfAlderLake ( [ & ] ( )
2024-03-02 23:23:16 +00:00
{
2024-03-24 15:30:38 +00:00
if ( WaitBuffer : : Compare2 < T , true > ( pTargetAddress , uWordSize , pCompareAddress ) )
2024-03-02 23:23:16 +00:00
{
return false ;
}
return check ( pTargetAddress , pCompareAddress , uWordSize ) ;
2024-05-03 11:14:52 +00:00
} , pTargetAddress ) ;
2024-11-21 17:17:09 +00:00
# else
return false ;
# endif
2024-03-02 23:23:16 +00:00
}
2024-03-12 22:50:22 +00:00
WOAFASTPUB bool TryWaitOnAddressSpecialEx ( EWaitMethod eMethod ,
const void * pTargetAddress ,
const void * pCompareAddress ,
AuUInt8 uWordSize ,
const AuFunction < bool ( const void * , const void * , AuUInt8 ) > & check )
{
if ( ! check )
{
return TryWaitOnAddressSpecial ( eMethod , pTargetAddress , pCompareAddress , uWordSize ) ;
}
2024-11-21 17:17:09 +00:00
# if !defined(WOA_STRICTER_FIFO)
2024-03-12 22:50:22 +00:00
DO_OF_METHOD_TYPE ( return , TryWaitOnAddressSpecialExTmpl , pTargetAddress , pCompareAddress , uWordSize , check ) ;
2024-11-21 17:17:09 +00:00
# endif
2024-03-12 22:50:22 +00:00
return false ;
}
2024-03-02 23:23:16 +00:00
2024-03-12 22:50:22 +00:00
WOAFASTPUB void WakeNOnAddress ( const void * pTargetAddress ,
AuUInt8 uNMaximumThreads )
2023-03-12 15:27:28 +00:00
{
if ( IsWaitOnRecommended ( ) )
{
2023-08-30 23:50:54 +00:00
auto [ pWakeAddress , uDelta , uMask ] = DecodeAddress ( pTargetAddress , 1 ) ;
2024-03-03 00:25:10 +00:00
if ( uDelta )
{
SysWakeAllOnAddress ( pWakeAddress ) ;
}
else
{
SysWakeNOnAddress ( pWakeAddress , uNMaximumThreads ) ;
}
2023-03-12 15:27:28 +00:00
}
else
{
2023-07-30 08:34:39 +00:00
( void ) gProcessWaitables . IterateWake ( pTargetAddress , [ & ] ( WaitEntry & entry ) - > AuPair < bool , bool >
2023-03-12 15:27:28 +00:00
{
if ( ! uNMaximumThreads )
{
2023-06-12 17:31:10 +00:00
return AuMakePair ( false , false ) ;
2023-03-12 15:27:28 +00:00
}
2023-06-12 17:31:10 +00:00
bool bWake { } ;
2023-12-05 07:56:57 +00:00
if ( entry . TrySignalAddress ( pTargetAddress ) )
2023-03-12 15:27:28 +00:00
{
2023-06-12 17:31:10 +00:00
bWake = true ;
2023-03-12 15:27:28 +00:00
uNMaximumThreads - - ;
}
2023-06-12 17:31:10 +00:00
bool bCont = uNMaximumThreads ! = 0 ;
return AuMakePair ( bCont , bWake ) ;
2023-03-12 15:27:28 +00:00
} ) ;
}
}
2024-03-12 22:50:22 +00:00
WOAFASTPUB void WakeOnAddress ( const void * pTargetAddress )
2023-03-12 15:27:28 +00:00
{
WakeNOnAddress ( pTargetAddress , 1 ) ;
}
2024-03-12 22:50:22 +00:00
WOAFASTPUB void WakeAllOnAddress ( const void * pTargetAddress )
2023-03-12 15:27:28 +00:00
{
if ( IsWaitOnRecommended ( ) )
{
2023-08-30 23:50:54 +00:00
auto [ pWakeAddress , uDelta , uMask ] = DecodeAddress ( pTargetAddress , 1 ) ;
2024-03-03 00:25:10 +00:00
SysWakeAllOnAddress ( pWakeAddress ) ;
2023-03-12 15:27:28 +00:00
}
else
{
2023-07-30 08:34:39 +00:00
( void ) gProcessWaitables . IterateWake ( pTargetAddress , [ & ] ( WaitEntry & entry ) - > AuPair < bool , bool >
2023-03-12 15:27:28 +00:00
{
2023-12-05 07:56:57 +00:00
return AuMakePair ( true , entry . TrySignalAddress ( pTargetAddress ) ) ;
2023-03-12 15:27:28 +00:00
} ) ;
}
}
2023-06-12 17:31:10 +00:00
2024-03-12 22:50:22 +00:00
WOAFASTPUB bool WaitOnAddressSteady ( const void * pTargetAddress ,
const void * pCompareAddress ,
AuUInt8 uWordSize ,
AuUInt64 qwNanoseconds ,
AuOptional < bool > optAlreadySpun )
2024-11-21 17:17:09 +00:00
{
# if !defined(WOA_STRICTER_FIFO)
2023-12-10 18:21:35 +00:00
// Avoid emulated path dynamic TLS fetch without TLS section
// or various security checks
// or other such bloated thunks
2024-03-12 22:50:22 +00:00
if ( ! WaitBuffer : : Compare2 < EWaitMethod : : eNotEqual , true > ( pTargetAddress , uWordSize , pCompareAddress , kMax64 ) )
2023-12-10 18:21:35 +00:00
{
return true ;
}
2024-11-21 17:17:09 +00:00
# endif
2023-12-10 18:21:35 +00:00
2023-06-15 19:44:27 +00:00
bool bWaitOnAddress = IsWaitOnRecommended ( ) ;
if ( bWaitOnAddress )
{
auto [ pWaitAddress , uDelta , uMask ] = DecodeAddress ( pTargetAddress , uWordSize ) ;
2023-08-20 12:41:53 +00:00
auto pCompareAddress2 = AuReinterpretCast < const char * > ( pCompareAddress ) - uDelta ;
2023-06-15 19:44:27 +00:00
WaitState state ;
state . uDownsizeMask = uMask ;
2024-03-12 22:50:22 +00:00
state . compare = uMask ! = kMax64 ?
2023-06-15 19:44:27 +00:00
WaitBuffer : : From ( pCompareAddress2 , 4 ) :
WaitBuffer : : From ( pCompareAddress2 , uWordSize ) ;
2024-03-12 22:50:22 +00:00
state . uWordSize = uMask ! = kMax64 ? 4 : uWordSize ;
2023-06-15 19:44:27 +00:00
2023-10-30 14:50:28 +00:00
bool bSpun { } ;
if ( Primitives : : ThrdCfg : : gPreferWaitOnAddressAlwaysSpinNative & &
optAlreadySpun . value_or ( false ) )
{
if ( TryWaitOnAddress ( pTargetAddress , pCompareAddress , uWordSize ) )
{
return true ;
}
2024-03-12 22:50:22 +00:00
2023-10-30 14:50:28 +00:00
bSpun = true ;
}
2023-06-15 19:44:27 +00:00
if ( ! qwNanoseconds )
{
RunOSWaitOnAddressNoTimedNoErrors ( pWaitAddress , pCompareAddress2 , state ) ;
return true ;
}
else
{
state . qwNanosecondsAbs = qwNanoseconds ;
2023-10-30 14:50:28 +00:00
return RunOSWaitOnAddressTimedSteady ( pWaitAddress , pCompareAddress2 , state , bSpun ) ;
2023-06-15 19:44:27 +00:00
}
}
else
{
2023-10-30 14:50:28 +00:00
if ( Primitives : : ThrdCfg : : gPreferWaitOnAddressAlwaysSpin & &
optAlreadySpun . value_or ( false ) )
2023-06-15 19:44:27 +00:00
{
2023-08-23 15:43:43 +00:00
if ( TryWaitOnAddress ( pTargetAddress , pCompareAddress , uWordSize ) )
{
return true ;
}
2023-06-15 19:44:27 +00:00
}
2024-03-12 22:50:22 +00:00
return WaitOnAddressWide < EWaitMethod : : eNotEqual > ( pTargetAddress , pCompareAddress , uWordSize , { } , qwNanoseconds ? qwNanoseconds : AuOptional < AuUInt64 > { } , false , nullptr ) ;
2024-03-02 23:23:16 +00:00
}
return false ;
}
2024-03-12 22:50:22 +00:00
WOAFASTPUB bool WaitOnAddressSpecialSteady ( EWaitMethod eMethod ,
const void * pTargetAddress ,
const void * pCompareAddress ,
AuUInt8 uWordSize ,
AuUInt64 qwNanoseconds ,
AuOptional < bool > optAlreadySpun )
2024-03-02 23:23:16 +00:00
{
2024-11-21 17:17:09 +00:00
# if !defined(WOA_STRICTER_FIFO)
2024-03-02 23:23:16 +00:00
// Avoid emulated path dynamic TLS fetch without TLS section
// or various security checks
// or other such bloated thunks
2024-03-12 22:50:22 +00:00
if ( ! WaitBuffer : : Compare ( pTargetAddress , uWordSize , pCompareAddress , kMax64 , eMethod ) )
2024-03-02 23:23:16 +00:00
{
return true ;
}
2024-11-21 17:17:09 +00:00
# endif
2024-03-02 23:23:16 +00:00
bool bWaitOnAddress = IsWaitOnRecommended ( ) ;
if ( bWaitOnAddress )
{
auto [ pWaitAddress , uDelta , uMask ] = DecodeAddress ( pTargetAddress , uWordSize ) ;
auto pCompareAddress2 = AuReinterpretCast < const char * > ( pCompareAddress ) - uDelta ;
WaitState state ;
state . uDownsizeMask = uMask ;
2024-03-12 22:50:22 +00:00
state . compare = uMask ! = kMax64 ?
2024-03-02 23:23:16 +00:00
WaitBuffer : : From ( pCompareAddress2 , 4 ) :
WaitBuffer : : From ( pCompareAddress2 , uWordSize ) ;
2024-03-12 22:50:22 +00:00
state . uWordSize = uMask ! = kMax64 ? 4 : uWordSize ;
2024-03-02 23:23:16 +00:00
state . pCompare2 = pCompareAddress ;
2024-03-12 22:50:22 +00:00
state . eWaitMethod = eMethod ;
2024-03-02 23:23:16 +00:00
bool bSpun { } ;
if ( Primitives : : ThrdCfg : : gPreferWaitOnAddressAlwaysSpinNative & &
optAlreadySpun . value_or ( false ) )
{
2024-03-12 22:50:22 +00:00
if ( TryWaitOnAddressSpecial ( eMethod , pTargetAddress , pCompareAddress , uWordSize ) )
2024-03-02 23:23:16 +00:00
{
return true ;
}
bSpun = true ;
}
if ( ! qwNanoseconds )
{
2024-03-12 22:50:22 +00:00
DO_OF_METHOD_TYPE ( , RunOSWaitOnAddressEQNoTimedNoErrors , pWaitAddress , pCompareAddress2 , state ) ;
2024-03-02 23:23:16 +00:00
return true ;
}
else
{
state . qwNanosecondsAbs = qwNanoseconds ;
2024-03-12 22:50:22 +00:00
DO_OF_METHOD_TYPE ( return , RunOSWaitOnAddressEQTimedSteady , pWaitAddress , pCompareAddress2 , state , bSpun ) ;
2024-03-02 23:23:16 +00:00
}
}
else
{
if ( Primitives : : ThrdCfg : : gPreferWaitOnAddressAlwaysSpin & &
optAlreadySpun . value_or ( false ) )
{
2024-03-12 22:50:22 +00:00
if ( TryWaitOnAddressSpecial ( eMethod , pTargetAddress , pCompareAddress , uWordSize ) )
2024-03-02 23:23:16 +00:00
{
return true ;
}
}
2024-03-12 22:50:22 +00:00
DO_OF_METHOD_TYPE ( return , WaitOnAddressWide , pTargetAddress , pCompareAddress , uWordSize , { } , qwNanoseconds ? qwNanoseconds : AuOptional < AuUInt64 > { } , false , pCompareAddress ) ;
2023-06-15 19:44:27 +00:00
}
return false ;
}
2023-03-12 15:27:28 +00:00
}