Exit gracefully when the application is closed
This commit is contained in:
parent
4be888c213
commit
4a6ea59302
10 changed files with 115 additions and 79 deletions
|
@ -100,6 +100,11 @@ namespace ChocolArm64.State
|
||||||
TickCounter.Start();
|
TickCounter.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal bool Synchronize()
|
||||||
|
{
|
||||||
|
return Running;
|
||||||
|
}
|
||||||
|
|
||||||
internal void OnBreak(long Position, int Imm)
|
internal void OnBreak(long Position, int Imm)
|
||||||
{
|
{
|
||||||
Break?.Invoke(this, new AInstExceptionEventArgs(Position, Imm));
|
Break?.Invoke(this, new AInstExceptionEventArgs(Position, Imm));
|
||||||
|
|
|
@ -110,6 +110,8 @@ namespace ChocolArm64.Translation
|
||||||
if (OpcIndex == 0)
|
if (OpcIndex == 0)
|
||||||
{
|
{
|
||||||
MarkLabel(GetLabel(CurrBlock.Position));
|
MarkLabel(GetLabel(CurrBlock.Position));
|
||||||
|
|
||||||
|
EmitSynchronization();
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrOp.Emitter(this);
|
CurrOp.Emitter(this);
|
||||||
|
@ -117,6 +119,25 @@ namespace ChocolArm64.Translation
|
||||||
ILBlock.Add(new AILBarrier());
|
ILBlock.Add(new AILBarrier());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void EmitSynchronization()
|
||||||
|
{
|
||||||
|
EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||||
|
|
||||||
|
EmitPrivateCall(typeof(AThreadState), nameof(AThreadState.Synchronize));
|
||||||
|
|
||||||
|
EmitLdc_I4(0);
|
||||||
|
|
||||||
|
AILLabel LblContinue = new AILLabel();
|
||||||
|
|
||||||
|
Emit(OpCodes.Bne_Un_S, LblContinue);
|
||||||
|
|
||||||
|
EmitLdc_I8(0);
|
||||||
|
|
||||||
|
Emit(OpCodes.Ret);
|
||||||
|
|
||||||
|
MarkLabel(LblContinue);
|
||||||
|
}
|
||||||
|
|
||||||
public bool TryOptEmitSubroutineCall()
|
public bool TryOptEmitSubroutineCall()
|
||||||
{
|
{
|
||||||
if (CurrBlock.Next == null)
|
if (CurrBlock.Next == null)
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Audio
|
namespace Ryujinx.Audio
|
||||||
{
|
{
|
||||||
public interface IAalOutput
|
public interface IAalOutput : IDisposable
|
||||||
{
|
{
|
||||||
int OpenTrack(int SampleRate, int Channels, ReleaseCallback Callback);
|
int OpenTrack(int SampleRate, int Channels, ReleaseCallback Callback);
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.Audio.OpenAL
|
namespace Ryujinx.Audio.OpenAL
|
||||||
{
|
{
|
||||||
public class OpenALAudioOut : IAalOutput
|
public class OpenALAudioOut : IAalOutput, IDisposable
|
||||||
{
|
{
|
||||||
private const int MaxTracks = 256;
|
private const int MaxTracks = 256;
|
||||||
|
|
||||||
|
@ -222,10 +222,17 @@ namespace Ryujinx.Audio.OpenAL
|
||||||
Td.CallReleaseCallbackIfNeeded();
|
Td.CallReleaseCallbackIfNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
//If it's not slept it will waste cycles
|
//If it's not slept it will waste cycles.
|
||||||
Thread.Sleep(10);
|
Thread.Sleep(10);
|
||||||
}
|
}
|
||||||
while (KeepPolling);
|
while (KeepPolling);
|
||||||
|
|
||||||
|
foreach (Track Td in Tracks.Values)
|
||||||
|
{
|
||||||
|
Td.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
Tracks.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int OpenTrack(int SampleRate, int Channels, ReleaseCallback Callback)
|
public int OpenTrack(int SampleRate, int Channels, ReleaseCallback Callback)
|
||||||
|
@ -342,5 +349,18 @@ namespace Ryujinx.Audio.OpenAL
|
||||||
|
|
||||||
return PlaybackState.Stopped;
|
return PlaybackState.Stopped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool Disposing)
|
||||||
|
{
|
||||||
|
if (Disposing)
|
||||||
|
{
|
||||||
|
KeepPolling = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -190,19 +190,22 @@ namespace Ryujinx.HLE.HOS
|
||||||
{
|
{
|
||||||
if (Processes.TryRemove(ProcessId, out Process Process))
|
if (Processes.TryRemove(ProcessId, out Process Process))
|
||||||
{
|
{
|
||||||
Process.StopAllThreadsAsync();
|
|
||||||
Process.Dispose();
|
Process.Dispose();
|
||||||
|
|
||||||
if (Processes.Count == 0)
|
if (Processes.Count == 0)
|
||||||
{
|
{
|
||||||
Device.OnFinish(EventArgs.Empty);
|
Unload();
|
||||||
|
|
||||||
|
Device.Unload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool TryGetProcess(int ProcessId, out Process Process)
|
private void Unload()
|
||||||
{
|
{
|
||||||
return Processes.TryGetValue(ProcessId, out Process);
|
VsyncEvent.Dispose();
|
||||||
|
|
||||||
|
Scheduler.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@ -216,13 +219,8 @@ namespace Ryujinx.HLE.HOS
|
||||||
{
|
{
|
||||||
foreach (Process Process in Processes.Values)
|
foreach (Process Process in Processes.Values)
|
||||||
{
|
{
|
||||||
Process.StopAllThreadsAsync();
|
|
||||||
Process.Dispose();
|
Process.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
VsyncEvent.Dispose();
|
|
||||||
|
|
||||||
Scheduler.Dispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,6 +124,16 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
AllThreads[Thread].WaitSync.Set();
|
AllThreads[Thread].WaitSync.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ForceWakeUp(KThread Thread)
|
||||||
|
{
|
||||||
|
if (AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread))
|
||||||
|
{
|
||||||
|
SchedThread.WaitSync.Set();
|
||||||
|
SchedThread.WaitActivity.Set();
|
||||||
|
SchedThread.WaitSched.Set();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void ChangeCore(KThread Thread, int IdealCore, int CoreMask)
|
public void ChangeCore(KThread Thread, int IdealCore, int CoreMask)
|
||||||
{
|
{
|
||||||
lock (SchedLock)
|
lock (SchedLock)
|
||||||
|
|
|
@ -56,9 +56,7 @@ namespace Ryujinx.HLE.HOS
|
||||||
|
|
||||||
private ConcurrentDictionary<long, KThread> Threads;
|
private ConcurrentDictionary<long, KThread> Threads;
|
||||||
|
|
||||||
private KThread MainThread;
|
private List<Executable> Executables;
|
||||||
|
|
||||||
private List<Executable> Executables;
|
|
||||||
|
|
||||||
private Dictionary<long, string> SymbolTable;
|
private Dictionary<long, string> SymbolTable;
|
||||||
|
|
||||||
|
@ -155,7 +153,7 @@ namespace Ryujinx.HLE.HOS
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
MainThread = HandleTable.GetData<KThread>(Handle);
|
KThread MainThread = HandleTable.GetData<KThread>(Handle);
|
||||||
|
|
||||||
if (NeedsHbAbi)
|
if (NeedsHbAbi)
|
||||||
{
|
{
|
||||||
|
@ -182,24 +180,6 @@ namespace Ryujinx.HLE.HOS
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StopAllThreadsAsync()
|
|
||||||
{
|
|
||||||
if (Disposed)
|
|
||||||
{
|
|
||||||
throw new ObjectDisposedException(nameof(Process));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MainThread != null)
|
|
||||||
{
|
|
||||||
MainThread.Thread.StopExecution();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (KThread Thread in Threads.Values)
|
|
||||||
{
|
|
||||||
Thread.Thread.StopExecution();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int MakeThread(
|
public int MakeThread(
|
||||||
long EntryPoint,
|
long EntryPoint,
|
||||||
long StackTop,
|
long StackTop,
|
||||||
|
@ -389,12 +369,9 @@ namespace Ryujinx.HLE.HOS
|
||||||
|
|
||||||
if (Threads.Count == 0)
|
if (Threads.Count == 0)
|
||||||
{
|
{
|
||||||
if (ShouldDispose)
|
|
||||||
{
|
|
||||||
Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
Device.System.ExitProcess(ProcessId);
|
Device.System.ExitProcess(ProcessId);
|
||||||
|
|
||||||
|
Unload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,6 +385,35 @@ namespace Ryujinx.HLE.HOS
|
||||||
return Thread;
|
return Thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Unload()
|
||||||
|
{
|
||||||
|
if (Disposed || Threads.Count > 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Disposed = true;
|
||||||
|
|
||||||
|
foreach (object Obj in HandleTable.Clear())
|
||||||
|
{
|
||||||
|
if (Obj is KSession Session)
|
||||||
|
{
|
||||||
|
Session.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INvDrvServices.UnloadProcess(this);
|
||||||
|
|
||||||
|
AppletState.Dispose();
|
||||||
|
|
||||||
|
if (NeedsHbAbi && Executables.Count > 0 && Executables[0].FilePath.EndsWith(Homebrew.TemporaryNroSuffix))
|
||||||
|
{
|
||||||
|
File.Delete(Executables[0].FilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
Device.Log.PrintInfo(LogClass.Loader, $"Process {ProcessId} exiting...");
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Dispose(true);
|
Dispose(true);
|
||||||
|
@ -415,41 +421,21 @@ namespace Ryujinx.HLE.HOS
|
||||||
|
|
||||||
protected virtual void Dispose(bool Disposing)
|
protected virtual void Dispose(bool Disposing)
|
||||||
{
|
{
|
||||||
if (Disposing && !Disposed)
|
if (Disposing)
|
||||||
{
|
{
|
||||||
//If there is still some thread running, disposing the objects is not
|
|
||||||
//safe as the thread may try to access those resources. Instead, we set
|
|
||||||
//the flag to have the Process disposed when all threads finishes.
|
|
||||||
//Note: This may not happen if the guest code gets stuck on a infinite loop.
|
|
||||||
if (Threads.Count > 0)
|
if (Threads.Count > 0)
|
||||||
{
|
{
|
||||||
ShouldDispose = true;
|
foreach (KThread Thread in Threads.Values)
|
||||||
|
|
||||||
Device.Log.PrintInfo(LogClass.Loader, $"Process {ProcessId} waiting all threads terminate...");
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Disposed = true;
|
|
||||||
|
|
||||||
foreach (object Obj in HandleTable.Clear())
|
|
||||||
{
|
|
||||||
if (Obj is KSession Session)
|
|
||||||
{
|
{
|
||||||
Session.Dispose();
|
Thread.Thread.StopExecution();
|
||||||
|
|
||||||
|
Scheduler.ForceWakeUp(Thread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (NeedsHbAbi && Executables.Count > 0 && Executables[0].FilePath.EndsWith(Homebrew.TemporaryNroSuffix))
|
|
||||||
{
|
{
|
||||||
File.Delete(Executables[0].FilePath);
|
Unload();
|
||||||
}
|
}
|
||||||
|
|
||||||
INvDrvServices.UnloadProcess(this);
|
|
||||||
|
|
||||||
AppletState.Dispose();
|
|
||||||
|
|
||||||
Device.Log.PrintInfo(LogClass.Loader, $"Process {ProcessId} exiting...");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -309,6 +309,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
|
||||||
{
|
{
|
||||||
if (Disposing)
|
if (Disposing)
|
||||||
{
|
{
|
||||||
|
AudioOut.CloseTrack(Track);
|
||||||
|
|
||||||
UpdateEvent.Dispose();
|
UpdateEvent.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,6 @@ namespace Ryujinx.HLE
|
||||||
|
|
||||||
public Hid Hid { get; private set; }
|
public Hid Hid { get; private set; }
|
||||||
|
|
||||||
public event EventHandler Finish;
|
|
||||||
|
|
||||||
public Switch(IGalRenderer Renderer, IAalOutput AudioOut)
|
public Switch(IGalRenderer Renderer, IAalOutput AudioOut)
|
||||||
{
|
{
|
||||||
if (Renderer == null)
|
if (Renderer == null)
|
||||||
|
@ -78,10 +76,9 @@ namespace Ryujinx.HLE
|
||||||
Gpu.Fifo.DispatchCalls();
|
Gpu.Fifo.DispatchCalls();
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void OnFinish(EventArgs e)
|
internal void Unload()
|
||||||
{
|
{
|
||||||
System.Dispose();
|
VFs.Dispose();
|
||||||
Finish?.Invoke(this, e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@ -94,7 +91,6 @@ namespace Ryujinx.HLE
|
||||||
if (Disposing)
|
if (Disposing)
|
||||||
{
|
{
|
||||||
System.Dispose();
|
System.Dispose();
|
||||||
VFs.Dispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,16 +62,12 @@ namespace Ryujinx
|
||||||
|
|
||||||
using (GLScreen Screen = new GLScreen(Device, Renderer))
|
using (GLScreen Screen = new GLScreen(Device, Renderer))
|
||||||
{
|
{
|
||||||
Device.Finish += (Sender, Args) =>
|
|
||||||
{
|
|
||||||
Screen.Exit();
|
|
||||||
};
|
|
||||||
|
|
||||||
Screen.MainLoop();
|
Screen.MainLoop();
|
||||||
Device.OnFinish(EventArgs.Empty);
|
|
||||||
|
Device.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
Environment.Exit(0);
|
AudioOut.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue