aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjhorv <38920027+jhorv@users.noreply.github.com>2023-05-26 17:57:43 -0400
committerGitHub <noreply@github.com>2023-05-26 23:57:43 +0200
commit42b9c1e8fede88880454154f8c3683f1f8424ed9 (patch)
tree7299252239f3809a5fbd4637c34624052c3c933f /src
parent3b375525fbaded422fb2f9a9984a5770a3779fcb (diff)
Ryujinx.Ava: fixes for random hangs on exit (#4827)1.1.826
* Attempt at fixing hang on exit by ending the WindowNotificationManager notification loop, so that the Thread running it can exit. * explicitly apply the NotificationManager template to allow the notification loop to begin * NotificationHelper - remove explicity call to ApplyTemplate(). Change to ManualResetEventSlim so we can cancel the Wait on it. * add a timeout to AudioRenderSystem.Stop()'s waiting for the termination signal, log a warning if this timeout occurs, and continue execution * NotifiationHelper - cancel first, the CompleteAdding() * Remove AudioRenderSystem._terminationEvent, redundant * NotificationHelper - use host.Closing event to trigger cancellation instead of _notifationManager.DetachedFromLogicalTree * Change NotificationHelper to use an explicit Thread for background work. Wait on the cancellationToken's WaitHandle so the Thread doesn't have to deal with async. Wrap foreach in try/catch (OperationCanceledException) to swallow the escaping exception from the GetConsumingEnumerable(). * adjust formatting of AsyncWorkQueue constructor to use object initializers consistently * use AsyncWorkQueue to do everything I added in SetNotificationManager() * Revert "use AsyncWorkQueue to do everything I added in SetNotificationManager()" This reverts commit f0e78366b8776ec8e2fef8ab023c0db1833155d3. * use AsyncWorkQueue to handle the Thread-related changes previously made to NotificationHelper.SetNotificationHelper(). Wrap it in Lazy<T> and force instantiation in the TemplateApplied event handler to accomodate for the fact that AsyncWorkQueue starts immediately, and the notification dispatch loop was being delayed by _templateAppliedEvent. * impl changes suggested by AcK77 * impl changes suggested by AcK77 (more)
Diffstat (limited to 'src')
-rw-r--r--src/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs14
-rw-r--r--src/Ryujinx.Ava/UI/Helpers/NotificationHelper.cs35
-rw-r--r--src/Ryujinx.Common/AsyncWorkQueue.cs8
3 files changed, 25 insertions, 32 deletions
diff --git a/src/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs b/src/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs
index 53570243..1ad7b859 100644
--- a/src/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs
+++ b/src/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs
@@ -31,7 +31,6 @@ namespace Ryujinx.Audio.Renderer.Server
private AudioRendererRenderingDevice _renderingDevice;
private AudioRendererExecutionMode _executionMode;
private IWritableEvent _systemEvent;
- private ManualResetEvent _terminationEvent;
private MemoryPoolState _dspMemoryPoolState;
private VoiceContext _voiceContext;
private MixContext _mixContext;
@@ -83,7 +82,6 @@ namespace Ryujinx.Audio.Renderer.Server
public AudioRenderSystem(AudioRendererManager manager, IWritableEvent systemEvent)
{
_manager = manager;
- _terminationEvent = new ManualResetEvent(false);
_dspMemoryPoolState = MemoryPoolState.Create(MemoryPoolState.LocationType.Dsp);
_voiceContext = new VoiceContext();
_mixContext = new MixContext();
@@ -387,11 +385,6 @@ namespace Ryujinx.Audio.Renderer.Server
_isActive = false;
}
- if (_executionMode == AudioRendererExecutionMode.Auto)
- {
- _terminationEvent.WaitOne();
- }
-
Logger.Info?.Print(LogClass.AudioRenderer, $"Stopped renderer id {_sessionId}");
}
@@ -668,8 +661,6 @@ namespace Ryujinx.Audio.Renderer.Server
{
if (_isActive)
{
- _terminationEvent.Reset();
-
if (!_manager.Processor.HasRemainingCommands(_sessionId))
{
GenerateCommandList(out CommandList commands);
@@ -686,10 +677,6 @@ namespace Ryujinx.Audio.Renderer.Server
_isDspRunningBehind = true;
}
}
- else
- {
- _terminationEvent.Set();
- }
}
}
@@ -857,7 +844,6 @@ namespace Ryujinx.Audio.Renderer.Server
}
_manager.Unregister(this);
- _terminationEvent.Dispose();
_workBufferMemoryPin.Dispose();
if (MemoryManager is IRefCounted rc)
diff --git a/src/Ryujinx.Ava/UI/Helpers/NotificationHelper.cs b/src/Ryujinx.Ava/UI/Helpers/NotificationHelper.cs
index 7e2afb8b..f207c5fb 100644
--- a/src/Ryujinx.Ava/UI/Helpers/NotificationHelper.cs
+++ b/src/Ryujinx.Ava/UI/Helpers/NotificationHelper.cs
@@ -3,21 +3,20 @@ using Avalonia.Controls;
using Avalonia.Controls.Notifications;
using Avalonia.Threading;
using Ryujinx.Ava.Common.Locale;
+using Ryujinx.Common;
using System;
using System.Collections.Concurrent;
using System.Threading;
-using System.Threading.Tasks;
namespace Ryujinx.Ava.UI.Helpers
{
public static class NotificationHelper
{
- private const int MaxNotifications = 4;
+ private const int MaxNotifications = 4;
private const int NotificationDelayInMs = 5000;
private static WindowNotificationManager _notificationManager;
- private static readonly ManualResetEvent _templateAppliedEvent = new(false);
private static readonly BlockingCollection<Notification> _notifications = new();
public static void SetNotificationManager(Window host)
@@ -29,25 +28,31 @@ namespace Ryujinx.Ava.UI.Helpers
Margin = new Thickness(0, 0, 15, 40)
};
+ var maybeAsyncWorkQueue = new Lazy<AsyncWorkQueue<Notification>>(
+ () => new AsyncWorkQueue<Notification>(notification =>
+ {
+ Dispatcher.UIThread.Post(() =>
+ {
+ _notificationManager.Show(notification);
+ });
+ },
+ "UI.NotificationThread",
+ _notifications),
+ LazyThreadSafetyMode.ExecutionAndPublication);
+
_notificationManager.TemplateApplied += (sender, args) =>
{
- _templateAppliedEvent.Set();
+ // NOTE: Force creation of the AsyncWorkQueue.
+ _ = maybeAsyncWorkQueue.Value;
};
- Task.Run(async () =>
+ host.Closing += (sender, args) =>
{
- _templateAppliedEvent.WaitOne();
-
- foreach (var notification in _notifications.GetConsumingEnumerable())
+ if (maybeAsyncWorkQueue.IsValueCreated)
{
- Dispatcher.UIThread.Post(() =>
- {
- _notificationManager.Show(notification);
- });
-
- await Task.Delay(NotificationDelayInMs / MaxNotifications);
+ maybeAsyncWorkQueue.Value.Dispose();
}
- });
+ };
}
public static void Show(string title, string text, NotificationType type, bool waitingExit = false, Action onClick = null, Action onClose = null)
diff --git a/src/Ryujinx.Common/AsyncWorkQueue.cs b/src/Ryujinx.Common/AsyncWorkQueue.cs
index 80f8dcfe..746ef4ca 100644
--- a/src/Ryujinx.Common/AsyncWorkQueue.cs
+++ b/src/Ryujinx.Common/AsyncWorkQueue.cs
@@ -22,9 +22,11 @@ namespace Ryujinx.Common
_cts = new CancellationTokenSource();
_queue = collection;
_workerAction = callback;
- _workerThread = new Thread(DoWork) { Name = name };
-
- _workerThread.IsBackground = true;
+ _workerThread = new Thread(DoWork)
+ {
+ Name = name,
+ IsBackground = true
+ };
_workerThread.Start();
}