Exit gracefully when the application is closed

This commit is contained in:
gdkchan 2018-08-16 00:27:36 -03:00
parent 4be888c213
commit 4a6ea59302
10 changed files with 115 additions and 79 deletions

View file

@ -100,6 +100,11 @@ namespace ChocolArm64.State
TickCounter.Start();
}
internal bool Synchronize()
{
return Running;
}
internal void OnBreak(long Position, int Imm)
{
Break?.Invoke(this, new AInstExceptionEventArgs(Position, Imm));

View file

@ -110,6 +110,8 @@ namespace ChocolArm64.Translation
if (OpcIndex == 0)
{
MarkLabel(GetLabel(CurrBlock.Position));
EmitSynchronization();
}
CurrOp.Emitter(this);
@ -117,6 +119,25 @@ namespace ChocolArm64.Translation
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()
{
if (CurrBlock.Next == null)

View file

@ -1,6 +1,8 @@
using System;
namespace Ryujinx.Audio
{
public interface IAalOutput
public interface IAalOutput : IDisposable
{
int OpenTrack(int SampleRate, int Channels, ReleaseCallback Callback);

View file

@ -8,7 +8,7 @@ using System.Threading;
namespace Ryujinx.Audio.OpenAL
{
public class OpenALAudioOut : IAalOutput
public class OpenALAudioOut : IAalOutput, IDisposable
{
private const int MaxTracks = 256;
@ -222,10 +222,17 @@ namespace Ryujinx.Audio.OpenAL
Td.CallReleaseCallbackIfNeeded();
}
//If it's not slept it will waste cycles
//If it's not slept it will waste cycles.
Thread.Sleep(10);
}
while (KeepPolling);
foreach (Track Td in Tracks.Values)
{
Td.Dispose();
}
Tracks.Clear();
}
public int OpenTrack(int SampleRate, int Channels, ReleaseCallback Callback)
@ -342,5 +349,18 @@ namespace Ryujinx.Audio.OpenAL
return PlaybackState.Stopped;
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
KeepPolling = false;
}
}
}
}

View file

@ -190,19 +190,22 @@ namespace Ryujinx.HLE.HOS
{
if (Processes.TryRemove(ProcessId, out Process Process))
{
Process.StopAllThreadsAsync();
Process.Dispose();
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()
@ -216,13 +219,8 @@ namespace Ryujinx.HLE.HOS
{
foreach (Process Process in Processes.Values)
{
Process.StopAllThreadsAsync();
Process.Dispose();
}
VsyncEvent.Dispose();
Scheduler.Dispose();
}
}
}

View file

@ -124,6 +124,16 @@ namespace Ryujinx.HLE.HOS.Kernel
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)
{
lock (SchedLock)

View file

@ -56,9 +56,7 @@ namespace Ryujinx.HLE.HOS
private ConcurrentDictionary<long, KThread> Threads;
private KThread MainThread;
private List<Executable> Executables;
private List<Executable> Executables;
private Dictionary<long, string> SymbolTable;
@ -155,7 +153,7 @@ namespace Ryujinx.HLE.HOS
return false;
}
MainThread = HandleTable.GetData<KThread>(Handle);
KThread MainThread = HandleTable.GetData<KThread>(Handle);
if (NeedsHbAbi)
{
@ -182,24 +180,6 @@ namespace Ryujinx.HLE.HOS
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(
long EntryPoint,
long StackTop,
@ -389,12 +369,9 @@ namespace Ryujinx.HLE.HOS
if (Threads.Count == 0)
{
if (ShouldDispose)
{
Dispose();
}
Device.System.ExitProcess(ProcessId);
Unload();
}
}
@ -408,6 +385,35 @@ namespace Ryujinx.HLE.HOS
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()
{
Dispose(true);
@ -415,41 +421,21 @@ namespace Ryujinx.HLE.HOS
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)
{
ShouldDispose = true;
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)
foreach (KThread Thread in Threads.Values)
{
Session.Dispose();
Thread.Thread.StopExecution();
Scheduler.ForceWakeUp(Thread);
}
}
if (NeedsHbAbi && Executables.Count > 0 && Executables[0].FilePath.EndsWith(Homebrew.TemporaryNroSuffix))
else
{
File.Delete(Executables[0].FilePath);
Unload();
}
INvDrvServices.UnloadProcess(this);
AppletState.Dispose();
Device.Log.PrintInfo(LogClass.Loader, $"Process {ProcessId} exiting...");
}
}
}

View file

@ -309,6 +309,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
{
if (Disposing)
{
AudioOut.CloseTrack(Track);
UpdateEvent.Dispose();
}
}

View file

@ -27,8 +27,6 @@ namespace Ryujinx.HLE
public Hid Hid { get; private set; }
public event EventHandler Finish;
public Switch(IGalRenderer Renderer, IAalOutput AudioOut)
{
if (Renderer == null)
@ -78,10 +76,9 @@ namespace Ryujinx.HLE
Gpu.Fifo.DispatchCalls();
}
public virtual void OnFinish(EventArgs e)
internal void Unload()
{
System.Dispose();
Finish?.Invoke(this, e);
VFs.Dispose();
}
public void Dispose()
@ -94,7 +91,6 @@ namespace Ryujinx.HLE
if (Disposing)
{
System.Dispose();
VFs.Dispose();
}
}
}

View file

@ -62,16 +62,12 @@ namespace Ryujinx
using (GLScreen Screen = new GLScreen(Device, Renderer))
{
Device.Finish += (Sender, Args) =>
{
Screen.Exit();
};
Screen.MainLoop();
Device.OnFinish(EventArgs.Empty);
Device.Dispose();
}
Environment.Exit(0);
AudioOut.Dispose();
}
}
}