| privateProcessExitStatusWaitForExitCore() |
| { |
| switch(Interop.Sys.WaitForExitAndReap(this,ProcessId,outintexitCode,outintrawSignal)) |
| { |
| case-1: |
| thrownewWin32Exception(); |
| default: |
| ProcessExitStatusstatus=new(exitCode,false,rawSignal!=0?(PosixSignal)rawSignal:null); |
| OnProcessExited(); |
| returnstatus; |
| } |
| } |
| |
| privateboolTryWaitForExitCore(intmilliseconds,[NotNullWhen(true)]outProcessExitStatus?exitStatus) |
| { |
| switch(Interop.Sys.TryWaitForExit(this,ProcessId,milliseconds,outintexitCode,outintrawSignal)) |
| { |
| case-1: |
| thrownewWin32Exception(); |
| case1:// timeout |
| exitStatus=null; |
| returnfalse; |
| default: |
| exitStatus=new(exitCode,false,rawSignal!=0?(PosixSignal)rawSignal:null); |
| OnProcessExited(); |
| returntrue; |
| } |
| } |
| |
| privatestaticintGetProcessIdCore()=>thrownewPlatformNotSupportedException(); |
| |
| privateProcessExitStatusWaitForExitOrKillOnTimeoutCore(intmilliseconds) |
| { |
| switch(Interop.Sys.WaitForExitOrKillOnTimeout(this,ProcessId,_isGroupLeader,milliseconds,outintexitCode,outintrawSignal,outinthasTimedout)) |
| { |
| case-1: |
| thrownewWin32Exception(); |
| default: |
| ProcessExitStatusstatus=new(exitCode,hasTimedout==1,rawSignal!=0?(PosixSignal)rawSignal:null); |
| OnProcessExited(); |
| returnstatus; |
| } |
| } |
| |
| privateasyncTask<ProcessExitStatus>WaitForExitAsyncCore(CancellationTokencancellationToken) |
| { |
| if(!cancellationToken.CanBeCanceled) |
| { |
| returnawaitTask.Run(WaitForExitCore,cancellationToken).ConfigureAwait(false); |
| } |
| |
| CreatePipe(outSafeFileHandlereadHandle,outSafeFileHandlewriteHandle); |
| |
| using(readHandle) |
| using(writeHandle) |
| { |
| usingCancellationTokenRegistrationregistration=cancellationToken.Register(static state => |
| { |
| ((SafeFileHandle)state!).Close();// Close the write end of the pipe to signal cancellation |
| },writeHandle); |
| |
| returnawaitTask.Run(()=> |
| { |
| switch(Interop.Sys.TryWaitForExitCancellable(this,ProcessId,(int)readHandle.DangerousGetHandle(),outintexitCode,outintrawSignal)) |
| { |
| case-1: |
| thrownewWin32Exception(); |
| case1:// canceled |
| thrownewOperationCanceledException(cancellationToken); |
| default: |
| ProcessExitStatusstatus=new(exitCode,false,rawSignal!=0?(PosixSignal)rawSignal:null); |
| OnProcessExited(); |
| returnstatus; |
| } |
| },cancellationToken).ConfigureAwait(false); |
| } |
| } |
| |
| privateasyncTask<ProcessExitStatus>WaitForExitOrKillOnCancellationAsyncCore(CancellationTokencancellationToken) |
| { |
| if(!cancellationToken.CanBeCanceled) |
| { |
| returnawaitTask.Run(WaitForExitCore,cancellationToken).ConfigureAwait(false); |
| } |
| |
| CreatePipe(outSafeFileHandlereadHandle,outSafeFileHandlewriteHandle); |
| |
| using(readHandle) |
| using(writeHandle) |
| { |
| usingCancellationTokenRegistrationregistration=cancellationToken.Register(static state => |
| { |
| ((SafeFileHandle)state!).Close();// Close the write end of the pipe to signal cancellation |
| },writeHandle); |
| |
| returnawaitTask.Run(()=> |
| { |
| switch(Interop.Sys.TryWaitForExitCancellable(this,ProcessId,(int)readHandle.DangerousGetHandle(),outintexitCode,outintrawSignal)) |
| { |
| case-1: |
| thrownewWin32Exception(); |
| case1:// canceled |
| boolwasKilled=KillCore(throwOnError:false,entireProcessGroup:_isGroupLeader); |
| ProcessExitStatusstatus=WaitForExitCore(); |
| returnnewProcessExitStatus(status.ExitCode,wasKilled,status.Signal); |
| default: |
| ProcessExitStatusexitStatus=new(exitCode,false,rawSignal!=0?(PosixSignal)rawSignal:null); |
| OnProcessExited(); |
| returnexitStatus; |
| } |
| },cancellationToken).ConfigureAwait(false); |
| } |
| } |
WaitForExitOrKillOnTimeoutandWaitForExitOrKillOnCancellationAsyncmethods must not throw on timeout/cancellation, just kill the process (if it has not already exited) and returnProcessExitStatuswithCanceled=true(if the process was actually killed)runtime/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessExitStatus.cs
Lines 50 to 53 in fc42ca6
runtime/src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Windows.cs
Lines 400 to 511 in 3f5919d
runtime/src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Unix.cs
Lines 188 to 300 in a247583
pidfdandpollto wait for process exit was provided in Implement SafeProcessHandle APIs for Linux and other Unixes #124979SafeFileHandle.CreateAnonymousPipeAPI for creating pipe that is used for monitoring for cancellationWaitmethods need to be able to reap the process, but once they do they need to updateProcessWaitStateProcessWaitStatereaps the process first, theWait*methods should obtain the exit status from theresrc/libraries/System.Diagnostics.Process/tests/SafeProcessHandleTests.csintroduced by Introduce SafeProcessHandle.Start and ProcessId #126192 and reuse tests provided in Add new process management APIs to SafeProcessHandle #124375 and Implement SafeProcessHandle APIs for macOS #124923