فهرست منبع

Change to BlockingCollection, thanks to @tznind.

BDisp 8 ماه پیش
والد
کامیت
3e952df5f7

+ 1 - 11
Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs

@@ -754,17 +754,7 @@ internal class NetDriver : ConsoleDriver
                 _mainLoopDriver._netEvents._forceRead = true;
             }
 
-            if (!_ansiResponseTokenSource.IsCancellationRequested)
-            {
-                _mainLoopDriver._netEvents._waitForStart.Set ();
-
-                if (!_mainLoopDriver._waitForProbe.IsSet)
-                {
-                    _mainLoopDriver._waitForProbe.Set ();
-                }
-
-                _waitAnsiResponse.Wait (_ansiResponseTokenSource.Token);
-            }
+            _waitAnsiResponse.Wait (_ansiResponseTokenSource.Token);
         }
         catch (OperationCanceledException)
         {

+ 96 - 138
Terminal.Gui/ConsoleDrivers/NetDriver/NetEvents.cs

@@ -6,13 +6,8 @@ namespace Terminal.Gui;
 
 internal class NetEvents : IDisposable
 {
-    private readonly ManualResetEventSlim _inputReady = new (false);
     private CancellationTokenSource _inputReadyCancellationTokenSource;
-    internal readonly ManualResetEventSlim _waitForStart = new (false);
-
-    //CancellationTokenSource _waitForStartCancellationTokenSource;
-    private readonly ManualResetEventSlim _winChange = new (false);
-    private readonly ConcurrentQueue<InputResult?> _inputQueue = new ();
+    private readonly BlockingCollection<InputResult> _inputQueue = new (new ConcurrentQueue<InputResult> ());
     private readonly ConsoleDriver _consoleDriver;
     private ConsoleKeyInfo [] _cki;
     private bool _isEscSeq;
@@ -33,41 +28,20 @@ internal class NetEvents : IDisposable
 
     public InputResult? DequeueInput ()
     {
-        while (_inputReadyCancellationTokenSource != null
-               && !_inputReadyCancellationTokenSource.Token.IsCancellationRequested)
+        while (_inputReadyCancellationTokenSource is { })
         {
-            _waitForStart.Set ();
-            _winChange.Set ();
-
             try
             {
-                if (!_inputReadyCancellationTokenSource.Token.IsCancellationRequested)
-                {
-                    if (_inputQueue.Count == 0)
-                    {
-                        _inputReady.Wait (_inputReadyCancellationTokenSource.Token);
-                    }
-                }
+                return _inputQueue.Take (_inputReadyCancellationTokenSource.Token);
             }
             catch (OperationCanceledException)
             {
                 return null;
             }
-            finally
-            {
-                _inputReady.Reset ();
-            }
 
 #if PROCESS_REQUEST
             _neededProcessRequest = false;
 #endif
-            if (_inputQueue.Count > 0)
-            {
-                if (_inputQueue.TryDequeue (out InputResult? result))
-                {
-                    return result;
-                }
-            }
         }
 
         return null;
@@ -130,129 +104,120 @@ internal class NetEvents : IDisposable
         {
             try
             {
-                if (!_forceRead)
-                {
-                    _waitForStart.Wait (_inputReadyCancellationTokenSource.Token);
-                }
-            }
-            catch (OperationCanceledException)
-            {
-                return;
-            }
-
-            _waitForStart.Reset ();
-
-            if (_inputQueue.Count == 0 || _forceRead)
-            {
-                ConsoleKey key = 0;
-                ConsoleModifiers mod = 0;
-                ConsoleKeyInfo newConsoleKeyInfo = default;
-
-                while (_inputReadyCancellationTokenSource is { IsCancellationRequested: false })
+                if (_inputQueue.Count == 0 || _forceRead)
                 {
-                    ConsoleKeyInfo consoleKeyInfo;
-
-                    try
-                    {
-                        consoleKeyInfo = ReadConsoleKeyInfo (_inputReadyCancellationTokenSource.Token);
-                    }
-                    catch (OperationCanceledException)
-                    {
-                        return;
-                    }
+                    ConsoleKey key = 0;
+                    ConsoleModifiers mod = 0;
+                    ConsoleKeyInfo newConsoleKeyInfo = default;
 
-                    if (AnsiEscapeSequenceRequestUtils.IncompleteCkInfos is { })
+                    while (_inputReadyCancellationTokenSource is { IsCancellationRequested: false })
                     {
-                        AnsiEscapeSequenceRequestUtils.InsertArray (AnsiEscapeSequenceRequestUtils.IncompleteCkInfos, _cki);
-                    }
+                        ConsoleKeyInfo consoleKeyInfo;
 
-                    if ((consoleKeyInfo.KeyChar == (char)KeyCode.Esc && !_isEscSeq)
-                        || (consoleKeyInfo.KeyChar != (char)KeyCode.Esc && _isEscSeq))
-                    {
-                        if (_cki is null && consoleKeyInfo.KeyChar != (char)KeyCode.Esc && _isEscSeq)
+                        try
                         {
-                            _cki = AnsiEscapeSequenceRequestUtils.ResizeArray (
-                                                            new ConsoleKeyInfo (
-                                                                                (char)KeyCode.Esc,
-                                                                                0,
-                                                                                false,
-                                                                                false,
-                                                                                false
-                                                                               ),
-                                                            _cki
-                                                           );
+                            consoleKeyInfo = ReadConsoleKeyInfo (_inputReadyCancellationTokenSource.Token);
+                        }
+                        catch (OperationCanceledException)
+                        {
+                            return;
                         }
 
-                        _isEscSeq = true;
+                        if (AnsiEscapeSequenceRequestUtils.IncompleteCkInfos is { })
+                        {
+                            AnsiEscapeSequenceRequestUtils.InsertArray (AnsiEscapeSequenceRequestUtils.IncompleteCkInfos, _cki);
+                        }
 
-                        if ((_cki is { } && _cki [^1].KeyChar != Key.Esc && consoleKeyInfo.KeyChar != Key.Esc && consoleKeyInfo.KeyChar <= Key.Space)
-                            || (_cki is { } && _cki [^1].KeyChar != '\u001B' && consoleKeyInfo.KeyChar == 127)
-                            || (_cki is { } && char.IsLetter (_cki [^1].KeyChar) && char.IsLower (consoleKeyInfo.KeyChar) && char.IsLetter (consoleKeyInfo.KeyChar))
-                            || (_cki is { Length: > 2 } && char.IsLetter (_cki [^1].KeyChar) && char.IsLetter (consoleKeyInfo.KeyChar)))
+                        if ((consoleKeyInfo.KeyChar == (char)KeyCode.Esc && !_isEscSeq)
+                            || (consoleKeyInfo.KeyChar != (char)KeyCode.Esc && _isEscSeq))
                         {
-                            ProcessRequestResponse (ref newConsoleKeyInfo, ref key, _cki, ref mod);
-                            _cki = null;
-                            _isEscSeq = false;
+                            if (_cki is null && consoleKeyInfo.KeyChar != (char)KeyCode.Esc && _isEscSeq)
+                            {
+                                _cki = AnsiEscapeSequenceRequestUtils.ResizeArray (
+                                                                                   new (
+                                                                                        (char)KeyCode.Esc,
+                                                                                        0,
+                                                                                        false,
+                                                                                        false,
+                                                                                        false
+                                                                                       ),
+                                                                                   _cki
+                                                                                  );
+                            }
+
+                            _isEscSeq = true;
+
+                            if ((_cki is { } && _cki [^1].KeyChar != Key.Esc && consoleKeyInfo.KeyChar != Key.Esc && consoleKeyInfo.KeyChar <= Key.Space)
+                                || (_cki is { } && _cki [^1].KeyChar != '\u001B' && consoleKeyInfo.KeyChar == 127)
+                                || (_cki is { } && char.IsLetter (_cki [^1].KeyChar) && char.IsLower (consoleKeyInfo.KeyChar) && char.IsLetter (consoleKeyInfo.KeyChar))
+                                || (_cki is { Length: > 2 } && char.IsLetter (_cki [^1].KeyChar) && char.IsLetter (consoleKeyInfo.KeyChar)))
+                            {
+                                ProcessRequestResponse (ref newConsoleKeyInfo, ref key, _cki, ref mod);
+                                _cki = null;
+                                _isEscSeq = false;
+
+                                ProcessMapConsoleKeyInfo (consoleKeyInfo);
+                            }
+                            else
+                            {
+                                newConsoleKeyInfo = consoleKeyInfo;
+                                _cki = AnsiEscapeSequenceRequestUtils.ResizeArray (consoleKeyInfo, _cki);
+
+                                if (Console.KeyAvailable)
+                                {
+                                    continue;
+                                }
 
-                            ProcessMapConsoleKeyInfo (consoleKeyInfo);
+                                ProcessRequestResponse (ref newConsoleKeyInfo, ref key, _cki, ref mod);
+                                _cki = null;
+                                _isEscSeq = false;
+                            }
+
+                            break;
                         }
-                        else
+
+                        if (consoleKeyInfo.KeyChar == (char)KeyCode.Esc && _isEscSeq && _cki is { })
                         {
-                            newConsoleKeyInfo = consoleKeyInfo;
-                            _cki = AnsiEscapeSequenceRequestUtils.ResizeArray (consoleKeyInfo, _cki);
+                            ProcessRequestResponse (ref newConsoleKeyInfo, ref key, _cki, ref mod);
+                            _cki = null;
 
                             if (Console.KeyAvailable)
                             {
-                                continue;
+                                _cki = AnsiEscapeSequenceRequestUtils.ResizeArray (consoleKeyInfo, _cki);
+                            }
+                            else
+                            {
+                                ProcessMapConsoleKeyInfo (consoleKeyInfo);
                             }
 
-                            ProcessRequestResponse (ref newConsoleKeyInfo, ref key, _cki, ref mod);
-                            _cki = null;
-                            _isEscSeq = false;
+                            break;
                         }
 
-                        break;
-                    }
-
-                    if (consoleKeyInfo.KeyChar == (char)KeyCode.Esc && _isEscSeq && _cki is { })
-                    {
-                        ProcessRequestResponse (ref newConsoleKeyInfo, ref key, _cki, ref mod);
-                        _cki = null;
+                        ProcessMapConsoleKeyInfo (consoleKeyInfo);
 
-                        if (Console.KeyAvailable)
-                        {
-                            _cki = AnsiEscapeSequenceRequestUtils.ResizeArray (consoleKeyInfo, _cki);
-                        }
-                        else
+                        if (_retries > 0)
                         {
-                            ProcessMapConsoleKeyInfo (consoleKeyInfo);
+                            _retries = 0;
                         }
 
                         break;
                     }
-
-                    ProcessMapConsoleKeyInfo (consoleKeyInfo);
-
-                    if (_retries > 0)
-                    {
-                        _retries = 0;
-                    }
-
-                    break;
                 }
             }
-
-            _inputReady.Set ();
+            catch (OperationCanceledException)
+            {
+                return;
+            }
         }
 
         void ProcessMapConsoleKeyInfo (ConsoleKeyInfo consoleKeyInfo)
         {
-            _inputQueue.Enqueue (
-                                 new InputResult
-                                 {
-                                     EventType = EventType.Key, ConsoleKeyInfo = AnsiEscapeSequenceRequestUtils.MapConsoleKeyInfo (consoleKeyInfo)
-                                 }
-                                );
+            _inputQueue.Add (
+                             new ()
+                             {
+                                 EventType = EventType.Key, ConsoleKeyInfo = AnsiEscapeSequenceRequestUtils.MapConsoleKeyInfo (consoleKeyInfo)
+                             }
+                            );
             _isEscSeq = false;
         }
     }
@@ -297,17 +262,12 @@ internal class NetEvents : IDisposable
         {
             try
             {
-                _winChange.Wait (_inputReadyCancellationTokenSource.Token);
-                _winChange.Reset ();
-
                 RequestWindowSize (_inputReadyCancellationTokenSource.Token);
             }
             catch (OperationCanceledException)
             {
                 return;
             }
-
-            _inputReady.Set ();
         }
     }
 
@@ -327,12 +287,12 @@ internal class NetEvents : IDisposable
         int w = Math.Max (winWidth, 0);
         int h = Math.Max (winHeight, 0);
 
-        _inputQueue.Enqueue (
-                             new InputResult
-                             {
-                                 EventType = EventType.WindowSize, WindowSizeEvent = new WindowSizeEvent { Size = new (w, h) }
-                             }
-                            );
+        _inputQueue.Add (
+                         new ()
+                         {
+                             EventType = EventType.WindowSize, WindowSizeEvent = new () { Size = new (w, h) }
+                         }
+                        );
 
         return true;
     }
@@ -609,11 +569,9 @@ internal class NetEvents : IDisposable
     {
         var mouseEvent = new MouseEvent { Position = pos, ButtonState = buttonState };
 
-        _inputQueue.Enqueue (
-                             new InputResult { EventType = EventType.Mouse, MouseEvent = mouseEvent }
-                            );
-
-        _inputReady.Set ();
+        _inputQueue.Add (
+                         new () { EventType = EventType.Mouse, MouseEvent = mouseEvent }
+                        );
     }
 
     public enum EventType
@@ -726,7 +684,7 @@ internal class NetEvents : IDisposable
     {
         var inputResult = new InputResult { EventType = EventType.Key, ConsoleKeyInfo = cki };
 
-        _inputQueue.Enqueue (inputResult);
+        _inputQueue.Add (inputResult);
     }
 
     public void Dispose ()

+ 22 - 48
Terminal.Gui/ConsoleDrivers/NetDriver/NetMainLoop.cs

@@ -16,8 +16,7 @@ internal class NetMainLoop : IMainLoopDriver
 
     private readonly ManualResetEventSlim _eventReady = new (false);
     private readonly CancellationTokenSource _inputHandlerTokenSource = new ();
-    private readonly ConcurrentQueue<NetEvents.InputResult?> _resultQueue = new ();
-    internal readonly ManualResetEventSlim _waitForProbe = new (false);
+    private readonly BlockingCollection<NetEvents.InputResult> _resultQueue = new (new ConcurrentQueue<NetEvents.InputResult> ());
     private readonly CancellationTokenSource _eventReadyTokenSource = new ();
     private MainLoop _mainLoop;
 
@@ -27,12 +26,9 @@ internal class NetMainLoop : IMainLoopDriver
     /// <exception cref="ArgumentNullException"></exception>
     public NetMainLoop (ConsoleDriver consoleDriver = null)
     {
-        if (consoleDriver is null)
-        {
-            throw new ArgumentNullException (nameof (consoleDriver));
-        }
+        ArgumentNullException.ThrowIfNull (consoleDriver);
 
-        _netEvents = new NetEvents (consoleDriver);
+        _netEvents = new (consoleDriver);
     }
 
     void IMainLoopDriver.Setup (MainLoop mainLoop)
@@ -51,9 +47,7 @@ internal class NetMainLoop : IMainLoopDriver
 
     bool IMainLoopDriver.EventsPending ()
     {
-        _waitForProbe.Set ();
-
-        if (_mainLoop.CheckTimersAndIdleHandlers (out int waitTimeout))
+        if (_resultQueue.Count > 0 || _mainLoop.CheckTimersAndIdleHandlers (out int waitTimeout))
         {
             return true;
         }
@@ -83,6 +77,7 @@ internal class NetMainLoop : IMainLoopDriver
             return _resultQueue.Count > 0 || _mainLoop.CheckTimersAndIdleHandlers (out _);
         }
 
+        // If cancellation was requested then always return true
         return true;
     }
 
@@ -91,11 +86,11 @@ internal class NetMainLoop : IMainLoopDriver
         while (_resultQueue.Count > 0)
         {
             // Always dequeue even if it's null and invoke if isn't null
-            if (_resultQueue.TryDequeue (out NetEvents.InputResult? dequeueResult))
+            if (_resultQueue.TryTake (out NetEvents.InputResult dequeueResult))
             {
                 if (dequeueResult is { })
                 {
-                    ProcessInput?.Invoke (dequeueResult.Value);
+                    ProcessInput?.Invoke (dequeueResult);
                 }
             }
         }
@@ -110,8 +105,7 @@ internal class NetMainLoop : IMainLoopDriver
 
         _eventReady?.Dispose ();
 
-        _resultQueue?.Clear ();
-        _waitForProbe?.Dispose ();
+        _resultQueue?.Dispose();
         _netEvents?.Dispose ();
         _netEvents = null;
 
@@ -124,49 +118,29 @@ internal class NetMainLoop : IMainLoopDriver
         {
             try
             {
-                if (!_netEvents._forceRead && !_inputHandlerTokenSource.IsCancellationRequested)
+                if (_inputHandlerTokenSource.IsCancellationRequested)
                 {
-                    _waitForProbe.Wait (_inputHandlerTokenSource.Token);
+                    return;
                 }
-            }
-            catch (OperationCanceledException)
-            {
-                return;
-            }
-            finally
-            {
-                if (_waitForProbe.IsSet)
-                {
-                    _waitForProbe.Reset ();
-                }
-            }
 
-            if (_inputHandlerTokenSource.IsCancellationRequested)
-            {
-                return;
-            }
-
-            _inputHandlerTokenSource.Token.ThrowIfCancellationRequested ();
+                if (_resultQueue?.Count == 0 || _netEvents._forceRead)
+                {
+                    NetEvents.InputResult? result = _netEvents.DequeueInput ();
 
-            if (_resultQueue.Count == 0)
-            {
-                _resultQueue.Enqueue (_netEvents.DequeueInput ());
-            }
+                    if (result.HasValue)
+                    {
+                        _resultQueue?.Add (result.Value);
+                    }
+                }
 
-            try
-            {
-                while (_resultQueue.Count > 0 && _resultQueue.TryPeek (out NetEvents.InputResult? result) && result is null)
+                if (!_inputHandlerTokenSource.IsCancellationRequested && _resultQueue?.Count > 0)
                 {
-                    // Dequeue null values
-                    _resultQueue.TryDequeue (out _);
+                    _eventReady.Set ();
                 }
             }
-            catch (InvalidOperationException) // Peek can raise an exception
-            { }
-
-            if (_resultQueue.Count > 0)
+            catch (OperationCanceledException)
             {
-                _eventReady.Set ();
+                return;
             }
         }
     }