@@ -28,8 +28,9 @@ public partial class PSConsoleReadLine : IPSConsoleReadLineMockableMethods
28
28
private Thread _readKeyThread ;
29
29
private AutoResetEvent _readKeyWaitHandle ;
30
30
private AutoResetEvent _keyReadWaitHandle ;
31
- private AutoResetEvent _closingWaitHandle ;
32
- private WaitHandle [ ] _waitHandles ;
31
+ private ManualResetEvent _closingWaitHandle ;
32
+ private WaitHandle [ ] _threadProcWaitHandles ;
33
+ private WaitHandle [ ] _requestKeyWaitHandles ;
33
34
private bool _captureKeys ;
34
35
private readonly Queue < ConsoleKeyInfo > _savedKeys ;
35
36
private uint _prePSReadlineConsoleMode ;
@@ -73,8 +74,10 @@ private void ReadKeyThreadProc()
73
74
var stopwatch = new Stopwatch ( ) ;
74
75
while ( true )
75
76
{
76
- // Wait until ReadKey tells us to read a key.
77
- _readKeyWaitHandle . WaitOne ( ) ;
77
+ // Wait until ReadKey tells us to read a key (or it's time to exit).
78
+ int handleId = WaitHandle . WaitAny ( _singleton . _threadProcWaitHandles ) ;
79
+ if ( handleId == 1 ) // It was the _closingWaitHandle that was signaled.
80
+ break ;
78
81
79
82
stopwatch . Restart ( ) ;
80
83
while ( _mockableMethods . KeyAvailable ( ) )
@@ -127,7 +130,7 @@ private static ConsoleKeyInfo ReadKey()
127
130
// - the console is exiting
128
131
// - 300ms - to process events if we're idle
129
132
130
- handleId = WaitHandle . WaitAny ( _singleton . _waitHandles , 300 ) ;
133
+ handleId = WaitHandle . WaitAny ( _singleton . _requestKeyWaitHandles , 300 ) ;
131
134
if ( handleId != WaitHandle . WaitTimeout )
132
135
break ;
133
136
@@ -451,15 +454,30 @@ static PSConsoleReadLine()
451
454
452
455
_breakHandlerGcHandle = GCHandle . Alloc ( new BreakHandler ( _singleton . BreakHandler ) ) ;
453
456
NativeMethods . SetConsoleCtrlHandler ( ( BreakHandler ) _breakHandlerGcHandle . Target , true ) ;
454
- _singleton . _readKeyThread = new Thread ( _singleton . ReadKeyThreadProc ) { IsBackground = true } ;
455
- _singleton . _readKeyThread . Start ( ) ;
456
457
_singleton . _readKeyWaitHandle = new AutoResetEvent ( false ) ;
457
458
_singleton . _keyReadWaitHandle = new AutoResetEvent ( false ) ;
458
- _singleton . _closingWaitHandle = new AutoResetEvent ( false ) ;
459
- _singleton . _waitHandles = new WaitHandle [ ] { _singleton . _keyReadWaitHandle , _singleton . _closingWaitHandle } ;
459
+ _singleton . _closingWaitHandle = new ManualResetEvent ( false ) ;
460
+ _singleton . _requestKeyWaitHandles = new WaitHandle [ ] { _singleton . _keyReadWaitHandle , _singleton . _closingWaitHandle } ;
461
+ _singleton . _threadProcWaitHandles = new WaitHandle [ ] { _singleton . _readKeyWaitHandle , _singleton . _closingWaitHandle } ;
460
462
461
463
// This is only used for post-mortem debugging - 200 keys should be enough to reconstruct most command lines.
462
464
_lastNKeys = new HistoryQueue < ConsoleKeyInfo > ( 200 ) ;
465
+
466
+ // This is for a "being hosted in an alternate appdomain scenario" (the
467
+ // DomainUnload event is not raised for the default appdomain). It allows us
468
+ // to exit cleanly when the appdomain is unloaded but the process is not going
469
+ // away.
470
+ if ( ! AppDomain . CurrentDomain . IsDefaultAppDomain ( ) )
471
+ {
472
+ AppDomain . CurrentDomain . DomainUnload += ( x , y ) =>
473
+ {
474
+ _singleton . _closingWaitHandle . Set ( ) ;
475
+ _singleton . _readKeyThread . Join ( ) ; // may need to wait for history to be written
476
+ } ;
477
+ }
478
+
479
+ _singleton . _readKeyThread = new Thread ( _singleton . ReadKeyThreadProc ) { IsBackground = true } ;
480
+ _singleton . _readKeyThread . Start ( ) ;
463
481
}
464
482
465
483
private PSConsoleReadLine ( )
0 commit comments