2021-10-02 10:28:49 +00:00
/***
Copyright ( C ) 2021 J Reece Wilson ( a / k / a " Reece " ) . All rights reserved .
File : Loop . Unix . cpp
Date : 2021 - 10 - 1
Author : Reece
* * */
# include <Source/RuntimeInternal.hpp>
# include "Loop.Unix.hpp"
2024-08-02 01:23:09 +00:00
# include "ILoopSourceEx.hpp"
# include <poll.h>
2021-10-02 10:28:49 +00:00
2024-09-07 21:45:34 +00:00
// TODO:
# if defined(AURORA_IS_LINUX_DERIVED)
namespace Aurora : : IO : : UNIX
{
bool LinuxOverlappedYield ( bool bUserspaceOnly ) ;
}
# endif
2022-06-11 23:52:46 +00:00
namespace Aurora : : IO : : Loop
2021-10-02 10:28:49 +00:00
{
2024-08-02 01:23:09 +00:00
AuList < AuSPtr < ILoopSource > > WaitMultipleOrObjects ( const AuList < AuSPtr < ILoopSource > > & objects , bool bZeroTick , AuUInt32 dwTimeoutReq , bool bAllowOthers , bool & bTooMany )
{
# if defined(AURORA_HAS_NO_POSIX_POLL)
// do the WinNT falllback into loop queue.
//
// loop queues should have long term persistency in a user-space ABI (kqueue) or in the kernel (epoll)
// they may take longer to setup, may seem wasteful to create and throw away, but it's probably the best we can do under BSD kernels.
// why? kevents exist for posix aio objects. they dont use fds.
//
// BSDs with posix AIO based async file transactions, >2.2 linux kernels, macos with corefoundation interop with kqueues, and other posix kernels with alternative aio will probably need
// need to use the win32 64 <= handles path.
bTooMany = true ;
return false ;
# else
AuList < AuSPtr < ILoopSourceEx > > loopSourceExs ;
AuList < AuSPtr < ILoopSourceEx > > loopSourceExs2 ;
AuList < AuSPtr < ILoopSource > > triggered ;
AuList < pollfd > handleArray ;
AuList < AuPair < AuUInt , bool > > handleIndicies ;
2023-10-21 05:10:33 +00:00
2024-08-02 01:23:09 +00:00
try
{
loopSourceExs . reserve ( objects . size ( ) ) ;
loopSourceExs2 . reserve ( objects . size ( ) ) ;
handleArray . reserve ( objects . size ( ) ) ;
triggered . reserve ( triggered . size ( ) ) ;
handleIndicies . reserve ( triggered . size ( ) ) ;
for ( const auto & source : objects )
{
if ( ! source )
{
continue ;
}
if ( auto extended = AuDynamicCast < ILoopSourceEx > ( source ) )
{
loopSourceExs2 . push_back ( extended ) ;
if ( extended - > Singular ( ) )
{
auto handle = extended - > GetHandle ( ) ;
auto handleWrite = extended - > GetWriteHandle ( ) ;
auto i = loopSourceExs . size ( ) ;
loopSourceExs . push_back ( extended ) ;
if ( handle ! = - 1 )
{
pollfd poll ;
poll . fd = handle ;
poll . events = POLLIN ;
poll . revents = 0 ;
handleArray . push_back ( poll ) ;
handleIndicies . push_back ( AuMakePair ( i , false ) ) ;
}
if ( handleWrite ! = - 1 )
{
pollfd poll ;
poll . fd = handleWrite ;
poll . events = POLLOUT ;
poll . revents = 0 ;
handleArray . push_back ( poll ) ;
handleIndicies . push_back ( AuMakePair ( i , true ) ) ;
}
}
else
{
auto handles = extended - > GetHandles ( ) ;
auto handlesWrite = extended - > GetWriteHandles ( ) ;
auto i = loopSourceExs . size ( ) ;
loopSourceExs . push_back ( extended ) ;
for ( const auto & handle : handles )
{
pollfd poll ;
if ( handle = = - 1 )
{
continue ;
}
poll . fd = handle ;
poll . events = POLLIN ;
poll . revents = 0 ;
handleArray . push_back ( poll ) ;
handleIndicies . push_back ( AuMakePair ( i , false ) ) ;
}
for ( const auto & handle : handlesWrite )
{
pollfd poll ;
if ( handle = = - 1 )
{
continue ;
}
poll . fd = handle ;
poll . events = POLLOUT ;
poll . revents = 0 ;
handleArray . push_back ( poll ) ;
handleIndicies . push_back ( AuMakePair ( i , true ) ) ;
}
}
}
}
}
catch ( . . . )
{
return { } ;
}
for ( const auto & source : loopSourceExs2 )
{
source - > OnPresleep ( ) ;
}
AuUInt32 uTimeout { } ;
if ( bZeroTick )
{
uTimeout = 0 ;
}
else if ( ! dwTimeoutReq )
{
uTimeout = - 1 ;
}
else
{
uTimeout = dwTimeoutReq ;
}
int ret ;
do
{
ret = poll ( handleArray . data ( ) , handleArray . size ( ) , uTimeout ) ;
uTimeout = 0 ;
if ( ret > 0 )
{
for ( AU_ITERATE_N ( i , handleArray . size ( ) ) )
{
if ( ! handleArray [ i ] . revents )
{
continue ;
}
auto uIndex = AuGet < 0 > ( handleIndicies [ i ] ) ;
auto bRead = AuGet < 1 > ( handleIndicies [ i ] ) ;
auto pLoopSource = AuExchange ( loopSourceExs [ uIndex ] , nullptr ) ;
if ( ! pLoopSource )
{
continue ;
}
if ( ! pLoopSource - > OnTrigger ( handleArray [ i ] . fd ) )
{
loopSourceExs [ uIndex ] = pLoopSource ;
continue ;
}
triggered . push_back ( pLoopSource ) ;
if ( ! bAllowOthers )
{
break ;
}
}
}
}
while ( ret = = - 1 & &
errno = = EINTR ) ;
for ( const auto & source : loopSourceExs2 )
{
source - > OnFinishSleep ( ) ;
}
2024-09-07 21:45:34 +00:00
// TODO: ugly workaround (see: LSFromHdNonblocking rationale) for an ugly TODO issue implicating all targets (see public Loop.hpp)
{
# if defined(AURORA_IS_LINUX_DERIVED)
// Do not syscall after read or select again under Linux
UNIX : : LinuxOverlappedYield ( true ) ;
# else
IOYield ( ) ;
# endif
}
2024-08-02 01:23:09 +00:00
return triggered ;
# endif
}
2021-10-02 10:28:49 +00:00
}