2023-12-28 16:49:11 +00:00
/***
Copyright ( C ) 2023 J Reece Wilson ( a / k / a " Reece " ) . All rights reserved .
File : CompletionGroup . cpp
Date : 2023 - 12 - 28
Author : Reece
* * */
# include <Source/RuntimeInternal.hpp>
# include <Aurora/IO/IOExperimental.hpp>
# include "CompletionGroup.hpp"
# include "CompletionGroupAndedIOWorkItem.hpp"
namespace Aurora : : IO : : CompletionGroup
{
struct CompletionGroup ;
CompletionGroup : : CompletionGroup ( ) :
anyProbablyAlwaysPresentEvent ( this , false ) ,
andPlsDontAllocateFdIfUntouchedEvent ( this , true )
{
}
CompletionGroup : : ~ CompletionGroup ( )
{
this - > ResetMemoryPins ( ) ;
}
bool CompletionGroup : : HasCompleted ( )
{
return this - > uTriggered = = this - > uAdded & &
bool ( this - > uAdded ) ;
}
AuPair < AuUInt32 , AuUInt32 > CompletionGroup : : GetStats ( )
{
return AuMakePair ( this - > uTriggered , this - > uAdded ) ;
}
void CompletionGroup : : SetCallbacks ( const AuSPtr < ICompletionGroupHooks > & pCallbacks )
{
AU_LOCK_GUARD ( this - > mutex ) ;
this - > pCallbacks = pCallbacks ;
}
void CompletionGroup : : ResetMemoryPins ( )
{
AuResetMember ( this - > pCallbacks ) ;
AuResetMember ( this - > pAnyBarrier ) ;
AuResetMember ( this - > pAndBarrier ) ;
for ( const auto & pOld : this - > workItems )
{
pOld - > CleanupForGCWI ( ) ;
}
2024-01-06 04:18:13 +00:00
AuResetMember ( this - > callbackTicks ) ;
2024-01-11 12:19:54 +00:00
this - > bTerminated = true ;
2023-12-28 16:49:11 +00:00
}
bool CompletionGroup : : HasItemsActive ( )
{
return this - > workItems . size ( ) ;
}
2024-01-11 12:19:54 +00:00
void CompletionGroup : : DoIOTick ( bool bManual )
2023-12-28 16:49:11 +00:00
{
2024-01-02 07:06:42 +00:00
AuList < AuSPtr < ICompletionGroupWorkItem > > removedItems ;
2023-12-28 16:49:11 +00:00
{
2024-01-02 07:06:42 +00:00
AU_DEBUG_MEMCRUNCH ;
AU_LOCK_GUARD ( this - > mutex ) ;
for ( auto itr = this - > workItems . begin ( ) ;
itr ! = this - > workItems . end ( ) ;
)
2023-12-28 16:49:11 +00:00
{
2024-01-02 07:06:42 +00:00
if ( itr - > get ( ) - > HasCompletedForGCWI ( ) )
{
auto that = * itr ;
itr = this - > workItems . erase ( itr ) ;
2023-12-28 16:49:11 +00:00
2024-01-02 07:06:42 +00:00
this - > uTriggered + + ;
2023-12-28 16:49:11 +00:00
2024-01-02 07:06:42 +00:00
that - > CleanupForGCWI ( ) ;
if ( this - > pCallbacks )
2023-12-28 16:49:11 +00:00
{
2024-01-02 07:06:42 +00:00
removedItems . push_back ( that ) ;
2023-12-28 16:49:11 +00:00
}
}
2024-01-02 07:06:42 +00:00
else
{
itr + + ;
}
2023-12-28 16:49:11 +00:00
}
2024-01-02 07:06:42 +00:00
}
if ( auto pCallbacks = this - > pCallbacks )
{
for ( const auto & pRemoved : removedItems )
2023-12-28 16:49:11 +00:00
{
2024-01-02 07:06:42 +00:00
try
{
pCallbacks - > OnHandleComplete ( pRemoved ) ;
}
catch ( . . . )
{
SysPushErrorCatch ( ) ;
}
2023-12-28 16:49:11 +00:00
}
}
2024-01-06 04:18:13 +00:00
{
AU_LOCK_GUARD ( this - > mutex ) ;
for ( const auto & [ pCallback , bAny ] : this - > callbackTicks )
{
if ( ! bAny )
{
continue ;
}
try
{
pCallback - > InvokeManualTick ( ) ;
}
catch ( . . . )
{
SysPushErrorCatch ( ) ;
}
}
}
2024-01-11 12:19:54 +00:00
if ( this - > workItems . empty ( ) & &
( bManual | | ! this - > bIsNeverEnding ) )
2023-12-28 16:49:11 +00:00
{
this - > andPlsDontAllocateFdIfUntouchedEvent . Set ( ) ;
if ( AuExchange ( this - > pCallbacks , { } ) )
{
try
{
this - > pCallbacks - > OnComplete ( ) ;
}
catch ( . . . )
{
SysPushErrorCatch ( ) ;
}
}
2024-01-06 04:18:13 +00:00
{
AU_LOCK_GUARD ( this - > mutex ) ;
for ( const auto & [ pCallback , bAny ] : this - > callbackTicks )
{
if ( bAny )
{
continue ;
}
try
{
pCallback - > InvokeManualTick ( ) ;
}
catch ( . . . )
{
SysPushErrorCatch ( ) ;
}
}
}
2023-12-28 16:49:11 +00:00
// anyone else?
this - > ResetMemoryPins ( ) ;
}
}
void CompletionGroup : : AddWorkItem ( AuSPtr < ICompletionGroupWorkItem > pCompletable )
{
2024-01-11 12:19:54 +00:00
SysAssert ( ! this - > bTerminated , " Completion group already terminated " ) ;
2023-12-28 16:49:11 +00:00
AU_LOCK_GUARD ( this - > mutex ) ;
this - > workItems . push_back ( pCompletable ) ;
this - > uAdded + + ;
}
2024-01-06 04:18:13 +00:00
void CompletionGroup : : AddCallbackTick ( const AuSPtr < IIOProcessorManualInvoker > & pCallbackInvoker , bool bAny )
{
AU_LOCK_GUARD ( this - > mutex ) ;
this - > callbackTicks . push_back ( AuMakePair ( pCallbackInvoker , bAny ) ) ;
}
2024-01-11 12:19:54 +00:00
bool CompletionGroup : : IsNeverEnding ( )
{
return this - > bIsNeverEnding ;
}
void CompletionGroup : : SetNeverEnding ( bool bValue )
{
this - > bIsNeverEnding = bValue ;
}
2023-12-28 16:49:11 +00:00
AuSPtr < Loop : : ILoopSource > CompletionGroup : : ToAndLoopSource ( )
{
return this - > andPlsDontAllocateFdIfUntouchedEvent . GetLoopSource ( ) ;
}
AuSPtr < Loop : : ILoopSource > CompletionGroup : : ToAnyLoopSource ( )
{
return this - > anyProbablyAlwaysPresentEvent . GetLoopSource ( ) ;
}
AuSPtr < Loop : : ILSEvent > CompletionGroup : : GetTriggerLoopSource ( )
{
return this - > anyProbablyAlwaysPresentEvent . GetLoopSource ( ) ;
}
2024-01-05 12:06:17 +00:00
bool CompletionGroup : : WaitForAnyMS ( AuUInt32 uTimeoutOrZeroMS )
{
if ( auto pLoopSource = this - > ToAnyLoopSource ( ) )
{
return pLoopSource - > WaitOn ( uTimeoutOrZeroMS ) ;
}
else
{
return false ;
}
}
bool CompletionGroup : : WaitForAllMS ( AuUInt32 uTimeoutOrZeroMS )
{
if ( auto pLoopSource = this - > ToAndLoopSource ( ) )
{
return pLoopSource - > WaitOn ( uTimeoutOrZeroMS ) ;
}
else
{
return false ;
}
}
2023-12-28 16:49:11 +00:00
void CompletionGroup : : TryTrigger ( )
{
if ( auto pSource = GetTriggerLoopSource ( ) )
{
pSource - > Set ( ) ;
}
2024-01-11 12:19:54 +00:00
this - > DoIOTick ( true ) ;
2023-12-28 16:49:11 +00:00
}
AuSPtr < Async : : IWorkItem > CompletionGroup : : OnCompletion ( )
{
2024-01-02 07:06:42 +00:00
AU_LOCK_GUARD ( this - > cs ) ;
2023-12-28 16:49:11 +00:00
if ( this - > pAndBarrier )
{
return this - > pAndBarrier ;
}
auto pWorker = AuAsync : : GetCurrentWorkerPId ( ) . GetPool ( ) ;
if ( ! pWorker )
{
pWorker = AuUnsafeRaiiToShared ( AuAsync : : GetAsyncApp ( ) ) ;
}
auto pRet = AuMakeShared < CompletionGroupAndedIOWorkItem > ( ( AuAsync : : IThreadPoolInternal * ) AuStaticPointerCast < AuAsync : : ThreadPool > ( pWorker ) . get ( ) ,
AuWorkerPId_t { } ,
this - > SharedFromThis ( ) ) ;
if ( ! pRet )
{
SysPushErrorMemory ( ) ;
return { } ;
}
// prevent attaching a singular loop source to a loop queue multiple times
if ( this - > pAnyBarrier )
{
auto pEvent = this - > andPlsDontAllocateFdIfUntouchedEvent . GetLoopSource ( ) ;
if ( ! pEvent )
{
return { } ;
}
pRet - > SetSchedByLoopSource ( pEvent ) - > Dispatch ( ) ;
}
else
{
auto pEvent = this - > anyProbablyAlwaysPresentEvent . GetLoopSource ( ) ;
if ( ! pEvent )
{
return { } ;
}
pRet - > SetSchedByLoopSource ( pEvent ) - > Dispatch ( ) ;
this - > bNoAny = true ;
}
this - > pAndBarrier = pRet ;
return pRet ;
}
AuSPtr < Async : : IWorkItem > CompletionGroup : : OnSingleCompletion ( )
{
2024-01-02 07:06:42 +00:00
AU_LOCK_GUARD ( this - > cs ) ;
2023-12-28 16:49:11 +00:00
if ( this - > pAnyBarrier )
{
return this - > pAnyBarrier ;
}
if ( ! this - > bNoAny )
{
SysPushErrorGeneric ( " To prevent double LoopQueue::SourceAdd on the same source, you must not call ::OnSingleCompletion() after ::OnCompletion() in this specific order " ) ;
return { } ;
}
auto pRet = AuAsync : : NewFence ( ) ;
if ( ! pRet )
{
SysPushErrorNested ( ) ;
return { } ;
}
pRet - > SetSchedByLoopSource ( this - > anyProbablyAlwaysPresentEvent . GetLoopSource ( ) ) - > Dispatch ( ) ;
this - > pAnyBarrier = pRet ;
return pRet ;
}
AUKN_SYM AuSPtr < ICompletionGroup > NewCompletionGroup ( )
{
return AuMakeShared < CompletionGroup > ( ) ;
}
}