mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
Fixed WindowsDriver mem leak
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 ()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 ();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user