Fixed WindowsDriver mem leak

This commit is contained in:
Tigger Kindel
2023-10-05 09:14:51 -06:00
committed by Tig
parent e1e82e07a1
commit e4f3b97da0
7 changed files with 100 additions and 43 deletions

View File

@@ -242,7 +242,7 @@ namespace Terminal.Gui {
// BUGBUG: OverlappedTop is not cleared here, but it should be?
MainLoop?.Stop ();
MainLoop?.Dispose ();
MainLoop = null;
Driver?.End ();
Driver = null;

View File

@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using static Terminal.Gui.NetEvents;
namespace Terminal.Gui {
/// <summary>
@@ -205,5 +206,12 @@ namespace Terminal.Gui {
}
}
}
public void TearDown ()
{
_descriptorWatchers?.Clear ();
_mainLoop = null;
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using static Terminal.Gui.NetEvents;
namespace Terminal.Gui;
@@ -33,5 +34,9 @@ internal class FakeMainLoop : IMainLoopDriver {
KeyPressed?.Invoke (FakeConsole.MockKeyPresses.Pop ());
}
}
public void TearDown ()
{
}
}

View File

@@ -10,6 +10,7 @@ using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Text;
using static Terminal.Gui.NetEvents;
namespace Terminal.Gui;
class NetWinVTConsole {
@@ -1394,8 +1395,20 @@ internal class NetMainLoop : IMainLoopDriver {
ProcessInput?.Invoke (_inputResult.Dequeue ().Value);
}
}
public void TearDown ()
{
//throw new NotImplementedException ();
_inputResult?.Clear ();
_tokenSource?.Cancel ();
_tokenSource?.Dispose ();
_keyReady?.Dispose ();
_waitForProbe?.Dispose ();
_netEvents?.Dispose ();
_mainLoop = null;
}
}

View File

@@ -1739,7 +1739,7 @@ internal class WindowsDriver : ConsoleDriver {
//_mainLoop.Dispose ();
}
_mainLoop = null;
WinConsole?.Cleanup ();
WinConsole = null;
@@ -1774,7 +1774,8 @@ internal class WindowsMainLoop : IMainLoopDriver {
bool _winChanged;
Size _windowSize;
CancellationTokenSource _eventReadyTokenSource = new CancellationTokenSource ();
CancellationTokenSource _inputHandlerTokenSource = new CancellationTokenSource ();
// The records that we keep fetching
readonly Queue<WindowsConsole.InputRecord []> _resultQueue = new Queue<WindowsConsole.InputRecord []> ();
@@ -1790,22 +1791,30 @@ internal class WindowsMainLoop : IMainLoopDriver {
public WindowsMainLoop (ConsoleDriver consoleDriver = null)
{
_consoleDriver = consoleDriver ?? throw new ArgumentNullException (nameof(consoleDriver));
_consoleDriver = consoleDriver ?? throw new ArgumentNullException (nameof (consoleDriver));
_winConsole = ((WindowsDriver)consoleDriver).WinConsole;
}
void IMainLoopDriver.Setup (MainLoop mainLoop)
{
_mainLoop = mainLoop;
Task.Run (WindowsInputHandler);
Task.Run (WindowsInputHandler, _inputHandlerTokenSource.Token);
Task.Run (CheckWinChange);
}
void WindowsInputHandler ()
{
while (_mainLoop != null) {
_waitForProbe.Wait ();
_waitForProbe.Reset ();
try {
if (!_inputHandlerTokenSource.IsCancellationRequested) {
_waitForProbe.Wait (_inputHandlerTokenSource.Token);
}
} catch (OperationCanceledException) {
return;
} finally {
_waitForProbe.Reset ();
}
if (_resultQueue?.Count == 0) {
_resultQueue.Enqueue (_winConsole.ReadConsoleInput ());
@@ -1820,7 +1829,7 @@ internal class WindowsMainLoop : IMainLoopDriver {
while (_mainLoop != null) {
_winChange.Wait ();
_winChange.Reset ();
while (_mainLoop != null) {
Task.Delay (500).Wait ();
_windowSize = _winConsole.GetConsoleBufferWindow (out _);
@@ -1829,18 +1838,17 @@ internal class WindowsMainLoop : IMainLoopDriver {
break;
}
}
_winChanged = true;
_eventReady.Set ();
}
}
void IMainLoopDriver.Wakeup ()
{
//tokenSource.Cancel ();
_eventReady.Set ();
}
bool IMainLoopDriver.EventsPending ()
{
_waitForProbe.Set ();
@@ -1869,8 +1877,6 @@ internal class WindowsMainLoop : IMainLoopDriver {
_eventReadyTokenSource = new CancellationTokenSource ();
return true;
}
void IMainLoopDriver.Iteration ()
{
@@ -1886,17 +1892,21 @@ internal class WindowsMainLoop : IMainLoopDriver {
WinChanged?.Invoke (this, new SizeChangedEventArgs (_windowSize));
}
}
//public void Dispose ()
//{
// _eventReadyTokenSource?.Cancel ();
// _eventReadyTokenSource?.Dispose ();
// _eventReady?.Dispose ();
// _mainLoop = null;
// _winChange?.Dispose ();
// _waitForProbe?.Dispose ();
//}
void IMainLoopDriver.TearDown ()
{
_inputHandlerTokenSource?.Cancel ();
_inputHandlerTokenSource?.Dispose ();
_eventReadyTokenSource?.Cancel ();
_eventReadyTokenSource?.Dispose ();
_eventReady?.Dispose ();
_winChange?.Dispose ();
_waitForProbe?.Dispose ();
_mainLoop = null;
}
}
class WindowsClipboard : ClipboardBase {

View File

@@ -16,6 +16,9 @@ namespace Terminal.Gui {
/// <summary>
/// Initializes the <see cref="MainLoop"/>, gets the calling main loop for the initialization.
/// </summary>
/// <remarks>
/// Call <see cref="TearDown"/> to release resources.
/// </remarks>
/// <param name="mainLoop">Main loop.</param>
void Setup (MainLoop mainLoop);
@@ -34,6 +37,11 @@ namespace Terminal.Gui {
/// The iteration function.
/// </summary>
void Iteration ();
/// <summary>
/// Tears down the <see cref="MainLoop"/> driver. Releases resources created in <see cref="Setup"/>.
/// </summary>
void TearDown ();
}
/// <summary>
@@ -43,7 +51,7 @@ namespace Terminal.Gui {
/// Monitoring of file descriptors is only available on Unix, there
/// does not seem to be a way of supporting this on Windows.
/// </remarks>
public class MainLoop {
public class MainLoop : IDisposable {
internal SortedList<long, Timeout> _timeouts = new SortedList<long, Timeout> ();
readonly object _timeoutsLockToken = new object ();
@@ -76,7 +84,7 @@ namespace Terminal.Gui {
/// The current <see cref="IMainLoopDriver"/> in use.
/// </summary>
/// <value>The main loop driver.</value>
public IMainLoopDriver MainLoopDriver { get; }
public IMainLoopDriver MainLoopDriver { get; private set; }
/// <summary>
/// Invoked when a new timeout is added. To be used in the case
@@ -87,6 +95,9 @@ namespace Terminal.Gui {
/// <summary>
/// Creates a new MainLoop.
/// </summary>
/// <remarks>
/// Use <see cref="Dispose"/> to release resources.
/// </remarks>
/// <param name="driver">The <see cref="ConsoleDriver"/> instance
/// (one of the implementations FakeMainLoop, UnixMainLoop, NetMainLoop or WindowsMainLoop).</param>
public MainLoop (IMainLoopDriver driver)
@@ -294,17 +305,6 @@ namespace Terminal.Gui {
bool _running;
// BUGBUG: Stop is only called from MainLoopUnitTests.cs. As a result, the mainloop
// will never exit during other unit tests or normal execution.
/// <summary>
/// Stops the mainloop.
/// </summary>
public void Stop ()
{
_running = false;
MainLoopDriver.Wakeup ();
}
/// <summary>
/// Determines whether there are pending events to be processed.
/// </summary>
@@ -325,7 +325,7 @@ namespace Terminal.Gui {
/// Use this to process all pending events (timers, idle handlers and file watches).
///
/// <code>
/// while (main.EvenstPending ()) RunIteration ();
/// while (main.EventsPending ()) RunIteration ();
/// </code>
/// </remarks>
public void RunIteration ()
@@ -335,10 +335,10 @@ namespace Terminal.Gui {
RunTimers ();
}
}
MainLoopDriver.Iteration ();
bool runIdle = false;
var runIdle = false;
lock (_idleHandlersLock) {
runIdle = _idleHandlers.Count > 0;
}
@@ -361,5 +361,24 @@ namespace Terminal.Gui {
}
_running = prev;
}
/// <summary>
/// Stops the main loop driver and calls <see cref="IMainLoopDriver.Wakeup"/>.
/// </summary>
public void Stop ()
{
_running = false;
MainLoopDriver.Wakeup ();
}
/// <inheritdoc/>
public void Dispose ()
{
GC.SuppressFinalize (this);
Stop ();
_running = false;
MainLoopDriver?.TearDown ();
MainLoopDriver = null;
}
}
}

View File

@@ -613,8 +613,10 @@ namespace Terminal.Gui.ApplicationTests {
Application.MainLoop.Invoke (() => {
tf.Text = $"index{r.Next ()}";
Interlocked.Increment (ref tbCounter);
if (target == tbCounter) // On last increment wake up the check
if (target == tbCounter) {
// On last increment wake up the check
_wakeUp.Set ();
}
});
});
}