2022-04-05 10:11:19 +00:00
/***
Copyright ( C ) 2021 J Reece Wilson ( a / k / a " Reece " ) . All rights reserved .
2022-12-16 00:41:01 +00:00
File : AuProcess . Unix . cpp
2022-04-05 10:11:19 +00:00
File : Process . Linux . cpp
Date : 2021 - 6 - 12
Author : Reece
* * */
# include <RuntimeInternal.hpp>
2022-12-16 00:41:01 +00:00
# include "AuProcesses.hpp"
# include "AuProcess.Unix.hpp"
2022-04-05 10:11:19 +00:00
# include <unistd.h>
# include <fcntl.h>
# include <sys/syscall.h>
# include <sys/types.h>
# include <sys/wait.h>
2022-04-05 10:18:35 +00:00
2023-09-14 23:11:14 +00:00
# include <Source/IO/AuIOHandle.Unix.hpp>
2024-03-05 21:50:45 +00:00
# include <Source/IO/CompletionGroup/CompletionGroup.hpp>
2022-08-10 15:04:41 +00:00
2023-08-30 00:28:05 +00:00
# if defined(AURORA_COMPILER_CLANG)
// warning: enumeration values 'kEnumCount' and 'kEnumInvalid' not handled in switch [-Wswitch
# pragma clang diagnostic ignored "-Wswitch"
// Yea, I don't give a shit.
# endif
2022-08-10 15:36:03 +00:00
# if defined(AURORA_IS_LINUX_DERIVED)
# include <sys/prctl.h>
# include <setjmp.h>
# if !defined(CLONE_CLEAR_SIGHAND)
# define CLONE_CLEAR_SIGHAND 0x100000000ULL
# endif
2022-08-10 15:04:41 +00:00
# endif
2022-04-05 10:11:19 +00:00
2023-09-16 20:49:30 +00:00
# if defined(AURORA_PLATFORM_BSD)
# if defined(__FreeBSD__)
# include <sys/param.h>
# endif
# include <sys/cpuset.h>
# endif
# if defined(AURORA_IS_LINUX_DERIVED)
# include <sched.h>
# endif
2022-04-05 10:11:19 +00:00
namespace Aurora : : Processes
{
2024-10-12 15:28:18 +00:00
static AuRWRenterableLock gRWLock ;
2022-04-05 10:11:19 +00:00
static AuHashMap < pid_t , ProcessImpl * > gPidLookupMap ;
2022-06-11 23:52:46 +00:00
struct ProcessAliveLoopSource : AuLoop : : LSEvent
2022-05-04 19:34:46 +00:00
{
ProcessAliveLoopSource ( ) ;
virtual AuLoop : : ELoopSource GetType ( ) override ;
} ;
2024-10-12 15:28:18 +00:00
static void ConsumeChildDeathQueue ( ) ;
2022-05-04 19:34:46 +00:00
ProcessAliveLoopSource : : ProcessAliveLoopSource ( ) : LSEvent ( false , false , true )
{ }
AuLoop : : ELoopSource ProcessAliveLoopSource : : GetType ( )
{
return AuLoop : : ELoopSource : : eProcessDead ;
}
2023-08-21 16:48:42 +00:00
ProcessImpl : : ProcessImpl ( StartupParameters & & params ) : startup_ ( AuMove ( params ) )
2022-04-05 10:11:19 +00:00
{
AuIOFS : : NormalizePath ( this - > startup_ . process , this - > startup_ . process ) ;
2022-08-10 15:04:41 +00:00
if ( this - > startup_ . workingDirectory )
{
AuString a ;
AuIOFS : : NormalizePath ( a , this - > startup_ . workingDirectory . value ( ) ) ;
this - > startup_ . workingDirectory = a ;
}
2022-04-05 10:11:19 +00:00
this - > startup_ . args . insert ( startup_ . args . begin ( ) , startup_ . process ) ;
for ( const auto & arg : this - > startup_ . args )
{
this - > cargs_ . push_back ( arg . c_str ( ) ) ;
this - > debug_ + = arg + " " ;
}
this - > cargs_ . push_back ( nullptr ) ;
if ( this - > debug_ . size ( ) )
{
this - > debug_ . resize ( this - > debug_ . size ( ) - 1 ) ;
}
2022-04-13 14:43:38 +00:00
this - > type_ = this - > startup_ . type ;
2022-04-05 10:11:19 +00:00
}
ProcessImpl : : ~ ProcessImpl ( )
{
if ( this - > type_ = = ESpawnType : : eSpawnChildProcessWorker )
{
TryKill ( ) ;
Terminate ( ) ;
}
{
2022-04-05 10:24:48 +00:00
AU_LOCK_GUARD ( gRWLock - > AsWritable ( ) ) ;
2022-04-05 10:18:35 +00:00
AuTryRemove ( gPidLookupMap , this - > pidt_ ) ;
2022-04-05 10:11:19 +00:00
}
2024-03-05 21:50:45 +00:00
if ( auto & pGroup = this - > pCompletionGroup_ )
{
this - > bHasExited = true ;
AuStaticCast < IO : : CompletionGroup : : CompletionGroup > ( pGroup ) - > UnsafeRemoveItem ( AuUnsafeRaiiToShared ( this ) ) ;
}
2024-01-05 12:55:19 +00:00
2022-04-05 10:11:19 +00:00
ShutdownPipes ( ) ;
}
AuUInt ProcessImpl : : GetProcessId ( )
{
return this - > pidt_ ;
}
2023-12-24 06:22:58 +00:00
bool ProcessImpl : : HasExited ( )
2024-10-12 15:28:18 +00:00
{
ConsumeChildDeathQueue ( ) ;
2023-12-24 06:22:58 +00:00
return this - > bHasExited ;
}
2022-04-05 10:11:19 +00:00
void ProcessImpl : : ByeLol ( AuSInt code )
{
this - > exitCode_ = code ;
2023-12-24 06:22:58 +00:00
this - > bHasExited = true ;
2022-04-05 10:11:19 +00:00
if ( this - > finished_ )
{
this - > finished_ - > Set ( ) ;
}
2022-05-04 19:34:46 +00:00
if ( this - > loopSource_ )
{
this - > loopSource_ - > Set ( ) ;
}
2023-12-24 06:22:58 +00:00
if ( this - > fsStream_ )
{
this - > fsStream_ - > CheckProcess ( ) ;
}
if ( this - > fsErrorStream_ )
{
this - > fsErrorStream_ - > CheckProcess ( ) ;
}
2024-01-05 09:24:23 +00:00
2024-03-05 21:50:45 +00:00
if ( auto & pCompletionGroup = this - > pCompletionGroup_ )
2024-01-05 09:24:23 +00:00
{
2024-03-05 21:50:45 +00:00
pCompletionGroup - > TryTriggerLater ( ) ;
2024-01-05 09:24:23 +00:00
}
2022-04-05 10:11:19 +00:00
}
void ProcessImpl : : ShutdownPipes ( )
{
2022-06-23 12:25:20 +00:00
if ( ! this - > bDontRelOut_ )
{
if ( auto fd = AuExchange ( pipeStdOut_ [ 1 ] , { } ) )
{
: : close ( fd ) ;
}
}
if ( ! this - > bDontRelErr_ )
{
if ( auto fd = AuExchange ( pipeStdErr_ [ 1 ] , { } ) )
{
: : close ( fd ) ;
}
}
if ( ! this - > bDontRelIn_ )
{
if ( auto fd = AuExchange ( pipeStdIn_ [ 0 ] , { } ) )
{
: : close ( fd ) ;
}
}
2022-04-05 10:11:19 +00:00
}
bool ProcessImpl : : TryKill ( )
{
2022-04-05 10:24:48 +00:00
AU_LOCK_GUARD ( gRWLock - > AsReadable ( ) ) ;
2024-10-12 15:28:18 +00:00
ConsumeChildDeathQueue ( ) ;
2022-04-05 10:11:19 +00:00
if ( this - > alive_ )
{
2022-05-04 15:34:02 +00:00
if ( : : kill ( this - > pidt_ , SIGTERM ) = = 0 )
{
2023-08-11 15:51:42 +00:00
return this - > finished_ - > LockMS ( 500 ) ;
2022-05-04 15:34:02 +00:00
}
2022-04-05 10:11:19 +00:00
}
2022-04-05 10:18:35 +00:00
2022-04-05 10:11:19 +00:00
return true ;
}
bool ProcessImpl : : Terminate ( )
{
2022-04-05 10:24:48 +00:00
AU_LOCK_GUARD ( gRWLock - > AsReadable ( ) ) ;
2022-04-05 10:18:35 +00:00
2024-10-12 15:28:18 +00:00
ConsumeChildDeathQueue ( ) ;
2022-04-05 10:11:19 +00:00
if ( this - > alive_ )
{
return : : kill ( this - > pidt_ , SIGKILL ) = = 0 ;
}
2022-04-05 10:18:35 +00:00
2022-04-05 10:11:19 +00:00
return true ;
}
AuSPtr < Aurora : : Threading : : IWaitable > ProcessImpl : : AsWaitable ( )
{
return this - > finished_ ;
}
2022-06-12 13:53:35 +00:00
AuSPtr < AuLoop : : ILoopSource > ProcessImpl : : AsLoopSource ( )
2022-05-04 19:34:46 +00:00
{
return this - > loopSource_ ;
}
2022-04-05 10:11:19 +00:00
AuSInt ProcessImpl : : GetExitCode ( )
{
return this - > exitCode_ ;
}
bool ProcessImpl : : Read ( EStandardHandle stream , const AuMemoryViewStreamWrite & destination , bool nonblock )
{
2023-12-28 16:49:11 +00:00
destination . outVariable = 0 ;
2023-09-15 14:53:20 +00:00
if ( ! IO : : EStandardStreamIsValid ( stream ) | | ( stream = = EStandardHandle : : eInputStream ) )
{
SysPushErrorArg ( " Invalid Stream " ) ;
return false ;
}
if ( ! destination )
{
SysPushErrorArg ( ) ;
return false ;
}
auto handle = stream = = EStandardHandle : : eErrorStream ? this - > pipeStdErr_ [ 0 ] : this - > pipeStdOut_ [ 0 ] ;
2022-04-05 10:11:19 +00:00
if ( handle < 0 )
{
2022-04-13 14:43:38 +00:00
SysPushErrorUninitialized ( ) ;
2022-04-05 10:11:19 +00:00
return false ;
}
2022-05-04 15:34:02 +00:00
auto control = : : fcntl ( handle , F_GETFL ) ;
2022-04-05 10:11:19 +00:00
auto ref = control ;
if ( nonblock )
{
control | = O_NONBLOCK ;
}
else
{
control & = ~ O_NONBLOCK ;
}
if ( ref ! = control )
{
2022-05-04 15:34:02 +00:00
: : fcntl ( handle , F_SETFL , control ) ;
2022-04-05 10:11:19 +00:00
}
2022-04-13 14:43:38 +00:00
int tmp ;
do
{
2022-05-04 15:34:02 +00:00
tmp = : : read ( handle , destination . ptr , destination . length ) ;
2023-09-14 23:11:14 +00:00
}
while ( ( tmp = = - 1 & & errno = = EINTR ) ) ;
2022-04-13 14:43:38 +00:00
if ( tmp < = 0 )
2022-04-05 10:11:19 +00:00
{
2022-04-15 14:46:07 +00:00
if ( tmp = = 0 )
2022-04-13 14:43:38 +00:00
{
2022-04-15 14:46:07 +00:00
return nonblock ;
2022-04-13 14:43:38 +00:00
}
2022-04-15 14:46:07 +00:00
SysPushErrorMem ( ) ;
2022-04-05 10:11:19 +00:00
return false ;
}
destination . outVariable = tmp ;
return true ;
}
bool ProcessImpl : : Write ( const AuMemoryViewStreamRead & source )
{
2023-12-28 16:49:11 +00:00
source . outVariable = 0 ;
2022-04-05 10:18:35 +00:00
auto handle = this - > pipeStdIn_ [ 1 ] ;
2022-04-05 10:11:19 +00:00
if ( ! handle )
{
return false ;
}
2022-05-04 19:34:46 +00:00
auto control = : : fcntl ( handle , F_GETFL ) ;
auto ref = control ;
if ( /*nonblock*/ true )
{
control | = O_NONBLOCK ;
}
else
{
control & = ~ O_NONBLOCK ;
}
if ( ref ! = control )
{
: : fcntl ( handle , F_SETFL , control ) ;
}
return : : write ( handle , source . ptr , source . length ) = = source . length ;
2022-04-05 10:11:19 +00:00
}
2023-09-14 23:11:14 +00:00
static bool InitProcessStdHandles ( EStreamForward fwd , int * fds , AuIO : : EStandardStream stream , IO : : IIOHandle * pHandle )
2022-04-05 10:11:19 +00:00
{
2023-09-14 23:11:14 +00:00
AuOptionalEx < AuUInt64 > optHandle ;
bool bIsRead = stream = = AuIO : : EStandardStream : : eInputStream ;
2022-06-23 12:25:20 +00:00
switch ( fwd )
2022-04-05 10:11:19 +00:00
{
2023-09-14 23:11:14 +00:00
case EStreamForward : : eIOHandle :
optHandle = pHandle - > GetOSHandleSafe ( ) ;
if ( ! optHandle )
{
return false ;
}
if ( bIsRead )
{
fds [ 0 ] = dup ( ( int ) optHandle . value ( ) ) ;
}
else
{
fds [ 1 ] = dup ( ( int ) optHandle . value ( ) ) ;
}
break ;
2022-06-23 12:25:20 +00:00
case EStreamForward : : eCurrentProcess :
2023-09-14 23:11:14 +00:00
if ( stream = = AuIO : : EStandardStream : : eInputStream )
{
fds [ 0 ] = dup ( STDIN_FILENO ) ;
if ( fds [ 0 ] < 0 )
{
return false ;
}
}
else if ( stream = = AuIO : : EStandardStream : : eErrorStream )
{
fds [ 1 ] = dup ( STDERR_FILENO ) ;
if ( fds [ 1 ] < 0 )
{
return false ;
}
}
else if ( stream = = AuIO : : EStandardStream : : eOutputStream )
{
fds [ 1 ] = dup ( STDOUT_FILENO ) ;
if ( fds [ 1 ] < 0 )
{
return false ;
}
}
else
{
return false ;
}
2022-06-23 12:25:20 +00:00
break ;
case EStreamForward : : eAsyncPipe :
if ( : : pipe ( fds ) )
2022-04-05 10:11:19 +00:00
{
2022-04-13 14:43:38 +00:00
SysPushErrorMem ( ) ;
2022-04-05 10:11:19 +00:00
return false ;
}
2022-06-23 12:25:20 +00:00
break ;
case EStreamForward : : eNull :
2023-09-14 23:11:14 +00:00
if ( bIsRead )
{
2024-03-15 06:18:32 +00:00
fds [ 0 ] = PosixOpen ( " /dev/null " , O_RDWR ) ;
2023-09-14 23:11:14 +00:00
}
else
{
2024-03-15 06:18:32 +00:00
fds [ 1 ] = PosixOpen ( " /dev/null " , O_RDWR ) ;
2023-09-14 23:11:14 +00:00
}
2022-06-23 12:25:20 +00:00
break ;
2023-08-11 15:51:42 +00:00
case EStreamForward : : eNewConsoleWindow :
SysPushErrorGeneric ( " AuProcesses is not the right place for PTY support. At least not in this form (this level of abstraction only cares for pipes). " ) ;
2023-09-14 23:11:14 +00:00
return false ;
2022-04-05 10:11:19 +00:00
}
2023-09-14 23:11:14 +00:00
if ( fds [ 0 ] > 0 )
{
if ( ! AuIO : : SetFDShareAccess ( fds [ 0 ] , bIsRead ) )
{
return false ;
}
}
if ( fds [ 1 ] > 0 )
{
if ( ! AuIO : : SetFDShareAccess ( fds [ 1 ] , ! bIsRead ) )
{
return false ;
}
}
// Yea, I guess we can't really guard against threads racing to leak close on exec-less fds
// Let's just not care on UNIX.
// Worst case, we leak a daemons input/output FD to a different daemon of a differing permission level
// ...and somehow you can find that fd
// ...and probably dup it before ::start()
// ...and issue the right commands over the stream to do something bad
// Shouldn't need to worry about his for a while.
2022-06-23 12:25:20 +00:00
return true ;
}
2022-04-05 10:11:19 +00:00
2022-06-23 12:25:20 +00:00
bool ProcessImpl : : Init ( )
{
2023-09-14 23:11:14 +00:00
InitProcessStdHandles ( this - > startup_ . fwdOut , this - > pipeStdOut_ , AuIO : : EStandardStream : : eOutputStream , this - > startup_ . handleOutStream ) ;
InitProcessStdHandles ( this - > startup_ . fwdErr , this - > pipeStdErr_ , AuIO : : EStandardStream : : eErrorStream , this - > startup_ . handleErrorStream ) ;
InitProcessStdHandles ( this - > startup_ . fwdIn , this - > pipeStdIn_ , AuIO : : EStandardStream : : eInputStream , this - > startup_ . handleInputStream ) ;
2022-04-05 10:11:19 +00:00
2024-08-05 21:13:02 +00:00
if ( ! AuFS : : FileExists ( this - > startup_ . process ) )
{
SysPushErrorIO ( " No Process Module / Missing File " ) ;
return false ;
}
2022-05-04 19:34:46 +00:00
this - > loopSource_ = AuMakeShared < ProcessAliveLoopSource > ( ) ;
if ( ! this - > loopSource_ )
{
2024-08-05 21:13:02 +00:00
SysPushErrorMemory ( ) ;
return false ;
}
this - > pSemaphore_ = AuLoop : : NewLSSemaphoreSlow ( 0 ) ;
if ( ! this - > pSemaphore_ )
{
SysPushErrorIO ( " No sync " ) ;
2022-05-04 19:34:46 +00:00
return false ;
}
2024-08-05 21:13:02 +00:00
{
auto semaphoreFd = AuLoop : : DbgLoopSourceToReadFd ( this - > pSemaphore_ ) ;
int iFlags = fcntl ( semaphoreFd , F_GETFD , 0 ) ;
if ( iFlags < 0 )
{
SysPushErrorIO ( " fcntl error " ) ;
return false ;
}
iFlags & = ~ FD_CLOEXEC ;
if ( fcntl ( semaphoreFd , F_SETFD , iFlags ) < 0 )
{
SysPushErrorIO ( " fcntl error " ) ;
return false ;
}
}
2022-04-05 10:11:19 +00:00
this - > finished_ = AuThreadPrimitives : : EventShared ( false , false , true ) ;
2022-05-04 19:34:46 +00:00
if ( ! this - > finished_ )
{
2024-08-05 21:13:02 +00:00
SysPushErrorIO ( " No sync " ) ;
2022-05-04 19:34:46 +00:00
return false ;
}
2022-06-23 12:25:20 +00:00
if ( ( this - > startup_ . fwdIn = = EStreamForward : : eAsyncPipe ) | |
( this - > startup_ . fwdOut = = EStreamForward : : eAsyncPipe ) )
2022-05-04 19:34:46 +00:00
{
2023-08-11 15:51:42 +00:00
this - > fsHandle_ = AuIO : : IOHandleShared ( ) ;
2022-05-04 19:34:46 +00:00
if ( ! this - > fsHandle_ )
{
return false ;
}
this - > fsStream_ = AuMakeShared < ProcessPipeFileStream > ( ) ;
if ( ! this - > fsStream_ )
{
return false ;
}
2023-09-14 23:11:14 +00:00
this - > fsHandle_ - > InitFromPairMove ( this - > pipeStdOut_ [ 0 ] = = - 1 ? AuOptionalEx < AuUInt64 > { } : AuOptionalEx < AuUInt64 > { ( AuUInt64 ) this - > pipeStdOut_ [ 0 ] } ,
this - > pipeStdIn_ [ 1 ] = = - 1 ? AuOptionalEx < AuUInt64 > { } : AuOptionalEx < AuUInt64 > { ( AuUInt64 ) this - > pipeStdIn_ [ 1 ] } ) ;
2022-05-04 19:34:46 +00:00
this - > fsStream_ - > Init ( this - > fsHandle_ ) ;
2023-12-24 06:22:58 +00:00
this - > fsStream_ - > MakeProcess ( this ) ;
2022-05-04 19:34:46 +00:00
}
2022-06-23 12:25:20 +00:00
if ( this - > startup_ . fwdErr = = EStreamForward : : eAsyncPipe )
2022-05-04 19:34:46 +00:00
{
2023-08-11 15:51:42 +00:00
this - > fsErrorHandle_ = AuIO : : IOHandleShared ( ) ;
2022-05-04 19:34:46 +00:00
if ( ! this - > fsErrorHandle_ )
{
return false ;
}
this - > fsErrorStream_ = AuMakeShared < ProcessPipeFileStream > ( ) ;
if ( ! this - > fsErrorStream_ )
{
return false ;
}
2023-09-14 23:11:14 +00:00
this - > fsErrorHandle_ - > InitFromPairMove ( this - > pipeStdErr_ [ 0 ] = = - 1 ? AuOptionalEx < AuUInt64 > { } : AuOptionalEx < AuUInt64 > { ( AuUInt64 ) this - > pipeStdErr_ [ 0 ] } , { } ) ;
2022-05-04 19:34:46 +00:00
this - > fsErrorStream_ - > Init ( this - > fsErrorHandle_ ) ;
2023-12-24 06:22:58 +00:00
this - > fsErrorStream_ - > MakeProcess ( this ) ;
2022-05-04 19:34:46 +00:00
}
2024-03-05 21:50:45 +00:00
if ( auto pCompletionGroup = AuExchange ( this - > startup_ . pAutoJoinCompletionGroup , { } ) )
{
( void ) this - > TryAttachProcessExitToCompletionGroup ( pCompletionGroup ) ;
}
2022-05-04 19:34:46 +00:00
return true ;
2022-04-05 10:11:19 +00:00
}
2022-05-12 08:04:32 +00:00
AuSPtr < AuIO : : IAsyncTransaction > ProcessImpl : : NewAsyncTransaction ( )
2022-05-04 15:34:02 +00:00
{
2022-05-13 00:43:54 +00:00
return this - > fsStream_ ? this - > fsStream_ - > NewTransaction ( ) : AuSPtr < AuIO : : IAsyncTransaction > { } ;
2022-05-04 15:34:02 +00:00
}
2022-05-12 08:04:32 +00:00
AuSPtr < AuIO : : IAsyncTransaction > ProcessImpl : : NewErrorStreamAsyncTransaction ( )
2022-05-04 15:34:02 +00:00
{
2022-05-13 00:43:54 +00:00
return this - > fsErrorStream_ ? this - > fsErrorStream_ - > NewTransaction ( ) : AuSPtr < AuIO : : IAsyncTransaction > { } ;
2022-05-04 15:34:02 +00:00
}
2023-09-16 21:08:10 +00:00
AuSPtr < IO : : IIOHandle > ProcessImpl : : GetOutputAndInputHandles ( )
{
return this - > fsHandle_ ;
}
AuSPtr < IO : : IIOHandle > ProcessImpl : : GetErrorStreamHandle ( )
{
return this - > fsErrorHandle_ ;
}
2023-12-02 16:40:58 +00:00
AuSPtr < IO : : IStreamReader > ProcessImpl : : ToStreamReader ( EStandardHandle stream )
{
if ( stream = = EStandardHandle : : eErrorStream )
{
if ( auto pThat = this - > GetErrorStreamHandle ( ) )
{
2024-03-16 09:51:41 +00:00
if ( auto pThat2 = AuFS : : OpenBlockingFileStreamFromHandleShared ( pThat ) )
2023-12-02 16:40:58 +00:00
{
return { pThat2 , pThat2 - > ToStreamReader ( ) } ;
}
}
}
else
{
if ( auto pThat = this - > GetOutputAndInputHandles ( ) )
{
2024-03-16 09:51:41 +00:00
if ( auto pThat2 = AuFS : : OpenBlockingFileStreamFromHandleShared ( pThat ) )
2023-12-02 16:40:58 +00:00
{
return { pThat2 , pThat2 - > ToStreamReader ( ) } ;
}
}
}
return { } ;
}
AuSPtr < IO : : IStreamWriter > ProcessImpl : : ToStreamWriter ( )
{
if ( auto pThat = this - > GetErrorStreamHandle ( ) )
{
2024-03-16 09:51:41 +00:00
if ( auto pThat2 = AuFS : : OpenBlockingFileStreamFromHandleShared ( pThat ) )
2023-12-02 16:40:58 +00:00
{
return { pThat2 , pThat2 - > ToStreamWriter ( ) } ;
}
}
return { } ;
}
2022-08-10 15:04:41 +00:00
void ProcessImpl : : ForkMain ( )
{
2024-03-05 11:06:29 +00:00
PosixDoForkHooks ( ) ;
2024-01-21 18:41:53 +00:00
2024-08-05 21:13:02 +00:00
static const auto kForkMemSize = 10 * 1024 * 1024 ;
auto pHeapMemory = SysAllocateLarge ( kForkMemSize ) ;
if ( ! pHeapMemory )
{
return ;
}
AuMemoryViewWrite heapView { pHeapMemory , kForkMemSize } ;
AuMemory : : RequestHeapOfRegion heapObject ( heapView ) ;
2022-08-10 15:04:41 +00:00
{
2023-09-14 23:11:14 +00:00
: : dup2 ( this - > pipeStdIn_ [ 0 ] , STDIN_FILENO ) ;
: : close ( this - > pipeStdIn_ [ 0 ] ) ;
2022-08-10 15:04:41 +00:00
}
{
2023-09-14 23:11:14 +00:00
: : dup2 ( this - > pipeStdErr_ [ 1 ] , STDERR_FILENO ) ;
: : close ( this - > pipeStdErr_ [ 1 ] ) ;
2022-08-10 15:04:41 +00:00
}
{
2023-09-14 23:11:14 +00:00
: : dup2 ( this - > pipeStdOut_ [ 1 ] , STDOUT_FILENO ) ;
: : close ( this - > pipeStdOut_ [ 1 ] ) ;
2022-08-10 15:04:41 +00:00
}
2022-08-10 15:36:03 +00:00
# if defined(AURORA_IS_LINUX_DERIVED)
if ( this - > type_ = = ESpawnType : : eSpawnChildProcessWorker )
2022-08-10 15:04:41 +00:00
{
2022-08-10 15:36:03 +00:00
: : prctl ( PR_SET_PDEATHSIG , SIGTERM ) ;
2022-08-10 15:04:41 +00:00
}
2022-08-10 15:36:03 +00:00
# endif
2023-09-15 15:03:41 +00:00
if ( this - > type_ ! = ESpawnType : : eSpawnOvermap )
{
: : setsid ( ) ;
}
2022-08-10 15:04:41 +00:00
# if defined(AURORA_IS_XNU_DERIVED)
if ( this - > startup_ . workingDirectory )
{
: : pthread_chdir_np ( this - > startup_ . workingDirectory . value ( ) . c_str ( ) ) ;
}
# else
if ( this - > startup_ . workingDirectory )
{
2024-08-05 21:13:02 +00:00
: : chdir ( this - > startup_ . workingDirectory . value ( ) . c_str ( ) ) ;
2022-08-10 15:04:41 +00:00
}
# endif
2023-09-16 20:49:30 +00:00
if ( this - > startup_ . optAffinity )
{
auto affinity = this - > startup_ . optAffinity . Value ( ) ;
# if defined(__FreeBSD__)
cpuset_setid ( CPU_WHICH_PID , - 1 , ( cpusetid_t * ) & affinity . lower ) ; // I guess?
# elif defined(AURORA_IS_LINUX_DERIVED) || (defined(AURORA_IS_POSIX_DERIVED) && defined(_GNU_SOURCE))
cpu_set_t cpuset ;
CPU_ZERO ( & cpuset ) ;
AuUInt8 index { } ;
while ( affinity . CpuBitScanForward ( index , index ) )
{
CPU_SET ( index , & cpuset ) ;
index + + ;
}
if ( ! CPU_COUNT ( & cpuset ) )
{
return ;
}
# if defined(AURORA_IS_LINUX_DERIVED)
sched_setaffinity ( 0 , sizeof ( cpu_set_t ) , & cpuset ) ;
# else
pthread_setaffinity_np ( pthread_self ( ) , cpuset_size ( cpuSet ) , & cpuset ) ;
# endif
# elif defined(AURORA_IS_POSIX_DERIVED)
2024-08-05 21:13:02 +00:00
if ( auto cpuSet = heapObject - > ZAlloc < cpuset_t * > ( CPU_ALLOC_SIZE ( 512 ) ) ) //cpuset_alloc())
2023-09-16 20:49:30 +00:00
{
cpuset_init ( cpuSet ) ;
AuUInt8 index { } ;
while ( affinity . CpuBitScanForward ( index , index ) )
{
cpuset_set_cpu ( cpuSet , index , 1 ) ;
index + + ;
}
pthread_setaffinity_np ( pthread_self ( ) , cpuset_size ( cpuSet ) , cpuSet ) ;
2024-08-05 21:13:02 +00:00
//cpuset_free(cpuSet);
2023-09-16 20:49:30 +00:00
}
# else
// Who else?
# endif
}
2023-12-22 03:57:46 +00:00
if ( this - > startup_ . posixApplySandboxCOW )
{
this - > startup_ . posixApplySandboxCOW ( ) ;
}
2024-08-05 21:13:02 +00:00
auto pProcessPath = heapObject - > ZAlloc < char * > ( this - > startup_ . process . size ( ) + 1 ) ;
AuMemcpy ( pProcessPath , this - > startup_ . process . c_str ( ) , this - > startup_ . process . size ( ) ) ;
auto pArgsBlock = heapObject - > ZAlloc < void * * > ( ( this - > cargs_ . size ( ) + 1 ) * sizeof ( void * ) ) ;
for ( AU_ITERATE_N ( i , this - > cargs_ . size ( ) ) )
{
if ( auto pString = this - > cargs_ [ i ] )
{
auto uLength = strlen ( pString ) + 1 ;
auto pArg = heapObject - > ZAlloc < char * > ( uLength ) ;
AuMemcpy ( pArg , pString , uLength ) ;
pArgsBlock [ i ] = pArg ;
}
}
auto pEnvArgsBlock = heapObject - > ZAlloc < void * * > ( ( this - > startup_ . environmentVariables . size ( ) + 1 ) * sizeof ( void * ) ) ;
for ( AU_ITERATE_N ( i , this - > startup_ . environmentVariables . size ( ) ) )
{
auto & [ key , value ] = this - > startup_ . environmentVariables [ i ] ;
auto uLength = key . size ( ) + value . size ( ) + 2 ;
auto pArg = heapObject - > ZAlloc < char * > ( uLength ) ;
AuMemcpy ( pArg , key . data ( ) , key . size ( ) ) ;
pArg [ key . size ( ) ] = ' = ' ;
AuMemcpy ( pArg + key . size ( ) + 1 , value . data ( ) , value . size ( ) ) ;
pEnvArgsBlock [ i ] = pArg ;
}
{
auto semaphoreFd = AuLoop : : DbgLoopSourceToReadFd ( this - > pSemaphore_ ) ;
this - > pSemaphore_ - > AddOne ( ) ;
close ( semaphoreFd ) ;
}
PosixFDYeetus ( ) ;
: : execve ( pProcessPath , ( char * const * ) pArgsBlock , ( char * const * ) pEnvArgsBlock ) ; // https://pubs.opengroup.org/onlinepubs/9699919799/functions/execve.html
2022-08-10 15:04:41 +00:00
}
2022-04-05 10:11:19 +00:00
bool ProcessImpl : : Start ( )
{
this - > exitCode_ = 0x10110100 ;
2024-08-05 21:13:02 +00:00
if ( this - > startup_ . bInheritEnvironmentVariables )
{
for ( const auto & [ key , value ] : AuProcess : : EnvironmentGetAll ( ) )
{
this - > startup_ . environmentVariables . insert ( this - > startup_ . environmentVariables . begin ( ) , AuMakePair ( key , value ) ) ;
}
}
2022-04-05 10:11:19 +00:00
if ( this - > type_ = = ESpawnType : : eSpawnOvermap )
{
2023-09-14 23:11:14 +00:00
this - > ForkMain ( ) ;
2022-04-05 10:11:19 +00:00
return false ;
}
pid_t pid ;
{
2022-05-04 15:34:02 +00:00
pid = : : fork ( ) ;
2022-04-05 10:11:19 +00:00
if ( pid = = 0 )
{
2022-08-10 15:04:41 +00:00
this - > ForkMain ( ) ;
2023-09-23 07:15:50 +00:00
SysPanic ( ) ;
2022-04-13 14:43:38 +00:00
return false ;
}
else if ( pid > 0 )
{
2023-09-23 07:15:50 +00:00
if ( pipeStdOut_ [ 1 ] & &
pipeStdOut_ [ 1 ] ! = - 1 )
2022-04-05 10:11:19 +00:00
{
2022-04-13 14:43:38 +00:00
: : close ( AuExchange ( pipeStdOut_ [ 1 ] , 0 ) ) ;
}
2023-09-23 07:15:50 +00:00
if ( pipeStdErr_ [ 1 ] & &
pipeStdErr_ [ 1 ] ! = - 1 )
2022-04-13 14:43:38 +00:00
{
: : close ( AuExchange ( pipeStdErr_ [ 1 ] , 0 ) ) ;
2022-04-05 10:11:19 +00:00
}
2023-09-23 07:15:50 +00:00
if ( pipeStdIn_ [ 0 ] & &
pipeStdIn_ [ 0 ] ! = - 1 )
2022-04-13 14:43:38 +00:00
{
: : close ( AuExchange ( pipeStdIn_ [ 0 ] , 0 ) ) ;
}
this - > pidt_ = pid ;
2022-04-05 10:11:19 +00:00
this - > alive_ = true ;
2022-04-13 14:43:38 +00:00
{
2022-06-23 12:25:20 +00:00
AU_LOCK_GUARD ( gRWLock - > AsWritable ( ) ) ;
2022-04-13 14:43:38 +00:00
SysAssert ( AuTryInsert ( gPidLookupMap , pid , this ) ) ;
}
2022-04-05 10:11:19 +00:00
2024-08-05 21:13:02 +00:00
return this - > pSemaphore_ - > WaitOn ( 250 ) ;
2022-04-05 10:11:19 +00:00
}
else
{
2022-04-13 14:43:38 +00:00
return false ;
2022-04-05 10:11:19 +00:00
}
}
return true ;
}
2023-12-23 03:56:09 +00:00
2024-01-05 09:24:23 +00:00
bool ProcessImpl : : TryAttachProcessExitToCompletionGroup ( const AuSPtr < IO : : CompletionGroup : : ICompletionGroup > & pCompletionGroup )
{
2024-01-05 12:55:19 +00:00
if ( this - > pCompletionGroup_ | |
! pCompletionGroup )
2024-01-05 09:24:23 +00:00
{
return false ;
}
this - > pCompletionGroup_ = pCompletionGroup ;
2024-01-05 12:55:19 +00:00
pCompletionGroup - > AddWorkItem ( AuUnsafeRaiiToShared ( this ) ) ;
2024-03-05 21:50:45 +00:00
pCompletionGroup - > TryTriggerLater ( ) ;
2024-01-05 09:24:23 +00:00
return true ;
}
IO : : CompletionGroup : : ICompletionGroupWorkHandle * ProcessImpl : : ToCompletionGroupHandle ( )
{
return this ;
}
bool ProcessImpl : : HasCompletedForGCWI ( )
{
return this - > HasExited ( ) ;
}
void ProcessImpl : : CleanupForGCWI ( )
{
AuResetMember ( this - > pCompletionGroup_ ) ;
}
2023-12-23 03:56:09 +00:00
void ProcessImpl : : HookMainDeath ( )
{
if ( this - > type_ = = ESpawnType : : eSpawnChildProcessWorker )
{
this - > Terminate ( ) ;
}
}
2023-08-21 16:48:42 +00:00
AUKN_SYM IProcess * SpawnNew ( StartupParameters & & params )
2022-04-05 10:11:19 +00:00
{
2023-08-21 16:48:42 +00:00
auto ret = _new ProcessImpl ( AuMove ( params ) ) ;
2022-04-05 10:11:19 +00:00
if ( ! ret )
{
2022-04-13 14:43:38 +00:00
SysPushErrorMem ( ) ;
2022-04-05 10:11:19 +00:00
return { } ;
}
if ( ! ret - > Init ( ) )
{
2022-04-13 14:43:38 +00:00
SysPushErrorNested ( ) ;
2022-04-05 10:11:19 +00:00
delete ret ;
return { } ;
}
return ret ;
}
AUKN_SYM void SpawnRelease ( IProcess * process )
{
AuSafeDelete < ProcessImpl * > ( process ) ;
}
static void HandleChildTermiantion ( pid_t pid , int code )
{
auto handler = gPidLookupMap . find ( pid ) ;
2022-04-13 14:43:38 +00:00
if ( handler = = gPidLookupMap . end ( ) )
{
return ;
}
2022-04-05 10:11:19 +00:00
{
auto process = * handler ;
process . second - > ByeLol ( code ) ;
}
}
2024-10-12 15:28:18 +00:00
void ConsumeChildDeathQueue ( )
2022-04-05 10:11:19 +00:00
{
int code ;
pid_t pid ;
2024-10-12 15:28:18 +00:00
auto pLock = gRWLock - > AsReadable ( ) ;
if ( ! pLock - > TryLock ( ) )
2022-04-05 10:11:19 +00:00
{
2024-10-12 15:28:18 +00:00
return ;
}
2022-04-05 10:11:19 +00:00
2024-10-12 15:28:18 +00:00
while ( ( pid = waitpid ( ( pid_t ) - 1 , & code , WNOHANG ) ) )
{
if ( pid = = ( pid_t ) - 1 )
2022-04-05 10:11:19 +00:00
{
break ;
}
HandleChildTermiantion ( pid , code ) ;
}
2024-10-12 15:28:18 +00:00
pLock - > Unlock ( ) ;
}
static void SigChldHandler ( int )
{
ConsumeChildDeathQueue ( ) ;
2022-04-05 10:11:19 +00:00
}
void InitUnix ( )
{
2022-04-06 01:24:38 +00:00
struct sigaction action =
{
. sa_handler = SigChldHandler ,
. sa_flags = SA_ONSTACK
} ;
2022-05-04 15:34:02 +00:00
: : sigemptyset ( & action . sa_mask ) ;
: : sigaction ( SIGCHLD , & action , nullptr ) ;
2022-04-05 10:11:19 +00:00
}
2023-12-23 03:56:09 +00:00
void PosixProcessShutdown ( )
{
# if !defined(AURORA_IS_LINUX_DERIVED)
2023-12-25 07:49:50 +00:00
decltype ( gPidLookupMap ) cpy ;
{
AU_LOCK_GUARD ( gRWLock - > AsReadable ( ) ) ;
cpy = gPidLookupMap ;
}
for ( const auto & [ pid , pProcess ] : cpy )
2023-12-23 03:56:09 +00:00
{
2023-12-25 07:49:50 +00:00
pProcess - > HookMainDeath ( ) ;
2023-12-23 03:56:09 +00:00
}
# endif
}
2022-04-05 10:11:19 +00:00
void DeinitUnix ( )
{
2022-04-06 01:24:38 +00:00
struct sigaction action =
{
. sa_handler = SIG_DFL ,
. sa_flags = SA_ONSTACK | SA_NOCLDWAIT
} ;
2022-05-04 15:34:02 +00:00
: : sigemptyset ( & action . sa_mask ) ;
: : sigaction ( SIGCHLD , & action , nullptr ) ;
2022-04-06 01:24:38 +00:00
2023-12-23 03:56:09 +00:00
PosixProcessShutdown ( ) ;
2022-04-05 10:11:19 +00:00
}
2022-04-05 10:24:48 +00:00
}