@@ -27,6 +27,7 @@ public class SshCommand : IDisposable
27
27
private CommandAsyncResult _asyncResult ;
28
28
private AsyncCallback _callback ;
29
29
private EventWaitHandle _sessionErrorOccuredWaitHandle ;
30
+ private EventWaitHandle _commmandCancelledWaitHandle ;
30
31
private Exception _exception ;
31
32
private StringBuilder _result ;
32
33
private StringBuilder _error ;
@@ -203,6 +204,7 @@ internal SshCommand(ISession session, string commandText, Encoding encoding)
203
204
_encoding = encoding ;
204
205
CommandTimeout = Session . InfiniteTimeSpan ;
205
206
_sessionErrorOccuredWaitHandle = new AutoResetEvent ( initialState : false ) ;
207
+ _commmandCancelledWaitHandle = new AutoResetEvent ( initialState : false ) ;
206
208
207
209
_session . Disconnected += Session_Disconnected ;
208
210
_session . ErrorOccured += Session_ErrorOccured ;
@@ -419,20 +421,31 @@ public int EndExecuteWithStatus(IAsyncResult asyncResult)
419
421
/// <returns>Exit status of the operation.</returns>
420
422
public Task < int > ExecuteAsync ( )
421
423
{
422
- return ExecuteAsync ( default ) ;
424
+ return ExecuteAsync ( forceKill : false , default ) ;
423
425
}
424
426
425
427
/// <summary>
426
428
/// Executes the the command asynchronously.
427
429
/// </summary>
428
430
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to observe.</param>
429
431
/// <returns>Exit status of the operation.</returns>
430
- public async Task < int > ExecuteAsync ( CancellationToken cancellationToken )
432
+ public Task < int > ExecuteAsync ( CancellationToken cancellationToken )
433
+ {
434
+ return ExecuteAsync ( forceKill : false , cancellationToken ) ;
435
+ }
436
+
437
+ /// <summary>
438
+ /// Executes the the command asynchronously.
439
+ /// </summary>
440
+ /// <param name="forceKill">if true send SIGKILL instead of SIGTERM to cancel the command.</param>
441
+ /// <param name="cancellationToken">The <see cref="CancellationToken"/> to observe.</param>
442
+ /// <returns>Exit status of the operation.</returns>
443
+ public async Task < int > ExecuteAsync ( bool forceKill , CancellationToken cancellationToken )
431
444
{
432
445
#if NET || NETSTANDARD2_1_OR_GREATER
433
- await using var ctr = cancellationToken . Register ( CancelAsync , useSynchronizationContext : false ) . ConfigureAwait ( continueOnCapturedContext : false ) ;
446
+ await using var ctr = cancellationToken . Register ( ( ) => CancelAsync ( forceKill ) , useSynchronizationContext : false ) . ConfigureAwait ( continueOnCapturedContext : false ) ;
434
447
#else
435
- using var ctr = cancellationToken . Register ( CancelAsync , useSynchronizationContext : false ) ;
448
+ using var ctr = cancellationToken . Register ( ( ) => CancelAsync ( forceKill ) , useSynchronizationContext : false ) ;
436
449
#endif // NET || NETSTANDARD2_1_OR_GREATER
437
450
438
451
try
@@ -451,9 +464,12 @@ public async Task<int> ExecuteAsync(CancellationToken cancellationToken)
451
464
/// <summary>
452
465
/// Cancels command execution in asynchronous scenarios.
453
466
/// </summary>
454
- public void CancelAsync ( )
467
+ /// <param name="forceKill">if true send SIGKILL instead of SIGTERM.</param>
468
+ public void CancelAsync ( bool forceKill = false )
455
469
{
456
- _ = _channel ? . SendExitSignalRequest ( "TERM" , coreDumped : false , "Command execution has been cancelled." , "en" ) ;
470
+ var signal = forceKill ? "KILL" : "TERM" ;
471
+ _ = _channel ? . SendExitSignalRequest ( signal , coreDumped : false , "Command execution has been cancelled." , "en" ) ;
472
+ _ = _commmandCancelledWaitHandle . Set ( ) ;
457
473
}
458
474
459
475
/// <summary>
@@ -597,6 +613,7 @@ private void WaitOnHandle(WaitHandle waitHandle)
597
613
var waitHandles = new [ ]
598
614
{
599
615
_sessionErrorOccuredWaitHandle ,
616
+ _commmandCancelledWaitHandle ,
600
617
waitHandle
601
618
} ;
602
619
@@ -606,7 +623,8 @@ private void WaitOnHandle(WaitHandle waitHandle)
606
623
case 0 :
607
624
ExceptionDispatchInfo . Capture ( _exception ) . Throw ( ) ;
608
625
break ;
609
- case 1 :
626
+ case 1 : // Command cancelled
627
+ case 2 :
610
628
// Specified waithandle was signaled
611
629
break ;
612
630
case WaitHandle . WaitTimeout :
@@ -711,6 +729,9 @@ protected virtual void Dispose(bool disposing)
711
729
_sessionErrorOccuredWaitHandle = null ;
712
730
}
713
731
732
+ _commmandCancelledWaitHandle ? . Dispose ( ) ;
733
+ _commmandCancelledWaitHandle = null ;
734
+
714
735
_isDisposed = true ;
715
736
}
716
737
}
0 commit comments