Просмотр исходного кода

[WIP] Add support for events (#60)

* Add support for events, move concept of domains to IpcService

* Support waiting for KThread, remove some test code, other tweaks

* Use move handle on NIFM since I can't test that now, it's better to leave it how it was
gdkchan 8 лет назад
Родитель
Сommit
4314a8f3e5
100 измененных файлов с 1117 добавлено и 835 удалено
  1. 5 1
      Ryujinx.Audio/IAalOutput.cs
  2. 72 3
      Ryujinx.Audio/OpenAL/OpenALAudioOut.cs
  3. 4 0
      Ryujinx.Audio/ReleaseCallback.cs
  4. 62 0
      Ryujinx.Core/OsHle/AppletStateMgr.cs
  5. 4 4
      Ryujinx.Core/OsHle/CondVar.cs
  6. 0 12
      Ryujinx.Core/OsHle/FileDesc.cs
  7. 62 0
      Ryujinx.Core/OsHle/GlobalStateTable.cs
  8. 0 48
      Ryujinx.Core/OsHle/Handles/HDomain.cs
  9. 0 7
      Ryujinx.Core/OsHle/Handles/HEvent.cs
  10. 0 29
      Ryujinx.Core/OsHle/Handles/HSession.cs
  11. 0 30
      Ryujinx.Core/OsHle/Handles/HSessionObj.cs
  12. 4 0
      Ryujinx.Core/OsHle/Handles/KEvent.cs
  13. 5 34
      Ryujinx.Core/OsHle/Handles/KProcessHandleTable.cs
  14. 13 13
      Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs
  15. 28 0
      Ryujinx.Core/OsHle/Handles/KSession.cs
  16. 28 0
      Ryujinx.Core/OsHle/Handles/KSynchronizationObject.cs
  17. 2 2
      Ryujinx.Core/OsHle/Handles/KThread.cs
  18. 17 2
      Ryujinx.Core/OsHle/Horizon.cs
  19. 9 28
      Ryujinx.Core/OsHle/IdDictionary.cs
  20. 0 8
      Ryujinx.Core/OsHle/Ipc/IpcDomCmd.cs
  21. 19 98
      Ryujinx.Core/OsHle/Ipc/IpcHandler.cs
  22. 1 2
      Ryujinx.Core/OsHle/Ipc/IpcLog.cs
  23. 8 0
      Ryujinx.Core/OsHle/Ipc/IpcMagic.cs
  24. 4 44
      Ryujinx.Core/OsHle/Ipc/IpcMessage.cs
  25. 0 1
      Ryujinx.Core/OsHle/KernelErr.cs
  26. 5 5
      Ryujinx.Core/OsHle/Mutex.cs
  27. 32 15
      Ryujinx.Core/OsHle/Process.cs
  28. 2 2
      Ryujinx.Core/OsHle/ServiceCtx.cs
  29. 0 128
      Ryujinx.Core/OsHle/ServiceMgr.cs
  30. 2 2
      Ryujinx.Core/OsHle/Services/Acc/IManagerForApplication.cs
  31. 2 2
      Ryujinx.Core/OsHle/Services/Acc/IProfile.cs
  32. 2 4
      Ryujinx.Core/OsHle/Services/Acc/ServiceAcc.cs
  33. 7 0
      Ryujinx.Core/OsHle/Services/Am/AmErr.cs
  34. 8 0
      Ryujinx.Core/OsHle/Services/Am/FocusState.cs
  35. 2 4
      Ryujinx.Core/OsHle/Services/Am/IApplicationFunctions.cs
  36. 2 4
      Ryujinx.Core/OsHle/Services/Am/IApplicationProxy.cs
  37. 2 2
      Ryujinx.Core/OsHle/Services/Am/IAudioController.cs
  38. 18 21
      Ryujinx.Core/OsHle/Services/Am/ICommonStateGetter.cs
  39. 2 2
      Ryujinx.Core/OsHle/Services/Am/IDebugFunctions.cs
  40. 2 2
      Ryujinx.Core/OsHle/Services/Am/IDisplayController.cs
  41. 2 2
      Ryujinx.Core/OsHle/Services/Am/ILibraryAppletCreator.cs
  42. 2 2
      Ryujinx.Core/OsHle/Services/Am/ISelfController.cs
  43. 2 4
      Ryujinx.Core/OsHle/Services/Am/IStorage.cs
  44. 2 2
      Ryujinx.Core/OsHle/Services/Am/IStorageAccessor.cs
  45. 2 2
      Ryujinx.Core/OsHle/Services/Am/IWindowController.cs
  46. 9 0
      Ryujinx.Core/OsHle/Services/Am/MessageInfo.cs
  47. 8 0
      Ryujinx.Core/OsHle/Services/Am/OperationMode.cs
  48. 2 4
      Ryujinx.Core/OsHle/Services/Am/ServiceAppletOE.cs
  49. 2 2
      Ryujinx.Core/OsHle/Services/Apm/ISession.cs
  50. 2 4
      Ryujinx.Core/OsHle/Services/Apm/ServiceApm.cs
  51. 2 2
      Ryujinx.Core/OsHle/Services/Aud/IAudioDevice.cs
  52. 11 6
      Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs
  53. 24 3
      Ryujinx.Core/OsHle/Services/Aud/IAudioRenderer.cs
  54. 12 6
      Ryujinx.Core/OsHle/Services/Aud/ServiceAudOut.cs
  55. 2 4
      Ryujinx.Core/OsHle/Services/Aud/ServiceAudRen.cs
  56. 2 2
      Ryujinx.Core/OsHle/Services/Bsd/ServiceBsd.cs
  57. 2 2
      Ryujinx.Core/OsHle/Services/Friend/IFriendService.cs
  58. 2 4
      Ryujinx.Core/OsHle/Services/Friend/ServiceFriend.cs
  59. 2 2
      Ryujinx.Core/OsHle/Services/FspSrv/IDirectory.cs
  60. 2 2
      Ryujinx.Core/OsHle/Services/FspSrv/IFile.cs
  61. 2 3
      Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs
  62. 2 2
      Ryujinx.Core/OsHle/Services/FspSrv/IStorage.cs
  63. 2 4
      Ryujinx.Core/OsHle/Services/FspSrv/ServiceFspSrv.cs
  64. 2 2
      Ryujinx.Core/OsHle/Services/Hid/IActiveVibrationDeviceList.cs
  65. 2 2
      Ryujinx.Core/OsHle/Services/Hid/IAppletResource.cs
  66. 2 4
      Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs
  67. 151 0
      Ryujinx.Core/OsHle/Services/IpcService.cs
  68. 2 2
      Ryujinx.Core/OsHle/Services/Lm/ILogger.cs
  69. 2 6
      Ryujinx.Core/OsHle/Services/Lm/ServiceLm.cs
  70. 2 4
      Ryujinx.Core/OsHle/Services/Nifm/IGeneralService.cs
  71. 24 5
      Ryujinx.Core/OsHle/Services/Nifm/IRequest.cs
  72. 2 4
      Ryujinx.Core/OsHle/Services/Nifm/ServiceNifm.cs
  73. 2 2
      Ryujinx.Core/OsHle/Services/Ns/ServiceNs.cs
  74. 41 22
      Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs
  75. 0 24
      Ryujinx.Core/OsHle/Services/ObjHelper.cs
  76. 2 2
      Ryujinx.Core/OsHle/Services/Pctl/IParentalControlService.cs
  77. 2 4
      Ryujinx.Core/OsHle/Services/Pctl/ServicePctl.cs
  78. 2 2
      Ryujinx.Core/OsHle/Services/Pl/ServicePl.cs
  79. 119 0
      Ryujinx.Core/OsHle/Services/ServiceFactory.cs
  80. 2 2
      Ryujinx.Core/OsHle/Services/Set/ServiceSet.cs
  81. 2 2
      Ryujinx.Core/OsHle/Services/Set/ServiceSetSys.cs
  82. 2 2
      Ryujinx.Core/OsHle/Services/Sfdnsres/ServiceSfdnsres.cs
  83. 7 5
      Ryujinx.Core/OsHle/Services/Sm/ServiceSm.cs
  84. 2 2
      Ryujinx.Core/OsHle/Services/Ssl/ServiceSsl.cs
  85. 2 2
      Ryujinx.Core/OsHle/Services/Time/ISteadyClock.cs
  86. 2 2
      Ryujinx.Core/OsHle/Services/Time/ISystemClock.cs
  87. 2 2
      Ryujinx.Core/OsHle/Services/Time/ITimeZoneService.cs
  88. 2 4
      Ryujinx.Core/OsHle/Services/Time/ServiceTime.cs
  89. 3 5
      Ryujinx.Core/OsHle/Services/Vi/IApplicationDisplayService.cs
  90. 13 4
      Ryujinx.Core/OsHle/Services/Vi/IHOSBinderDriver.cs
  91. 2 2
      Ryujinx.Core/OsHle/Services/Vi/IManagerDisplayService.cs
  92. 2 2
      Ryujinx.Core/OsHle/Services/Vi/ISystemDisplayService.cs
  93. 14 8
      Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs
  94. 2 4
      Ryujinx.Core/OsHle/Services/Vi/ServiceVi.cs
  95. 103 48
      Ryujinx.Core/OsHle/Svc/SvcSystem.cs
  96. 10 8
      Ryujinx.Core/OsHle/Svc/SvcThread.cs
  97. 3 3
      Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs
  98. 5 5
      Ryujinx.Core/Switch.cs
  99. 44 15
      Ryujinx.Graphics/Gpu/NsGpuPGraph.cs
  100. 1 0
      Ryujinx.Graphics/Gpu/NsGpuRegister.cs

+ 5 - 1
Ryujinx.Audio/IAalOutput.cs

@@ -2,7 +2,11 @@ namespace Ryujinx.Audio
 {
     public interface IAalOutput
     {
-        int OpenTrack(int SampleRate, int Channels, out AudioFormat Format);
+        int OpenTrack(
+            int             SampleRate,
+            int             Channels,
+            ReleaseCallback Callback,
+            out AudioFormat Format);
 
         void CloseTrack(int Track);
 

+ 72 - 3
Ryujinx.Audio/OpenAL/OpenALAudioOut.cs

@@ -3,6 +3,7 @@ using OpenTK.Audio.OpenAL;
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
+using System.Threading;
 
 namespace Ryujinx.Audio.OpenAL
 {
@@ -22,20 +23,27 @@ namespace Ryujinx.Audio.OpenAL
             
             public ALFormat Format { get; private set; }
 
+            private ReleaseCallback Callback;
+
             public PlaybackState State { get; set; }
 
+            private bool ShouldCallReleaseCallback;
+
             private ConcurrentDictionary<long, int> Buffers;
 
             private Queue<long> QueuedTagsQueue;
 
             private Queue<long> ReleasedTagsQueue;
 
+            private int LastReleasedCount;
+
             private bool Disposed;
 
-            public Track(int SampleRate, ALFormat Format)
+            public Track(int SampleRate, ALFormat Format, ReleaseCallback Callback)
             {
                 this.SampleRate = SampleRate;
                 this.Format     = Format;
+                this.Callback   = Callback;
 
                 State = PlaybackState.Stopped;
 
@@ -109,11 +117,42 @@ namespace Ryujinx.Audio.OpenAL
 
                 AL.GetSource(SourceId, ALGetSourcei.BuffersProcessed, out int ReleasedCount);
 
+                CheckReleaseChanges(ReleasedCount);
+
                 if (ReleasedCount > 0)
                 {
                     AL.SourceUnqueueBuffers(SourceId, ReleasedCount);
                 }
             }
+
+            public void CallReleaseCallbackIfNeeded()
+            {
+                CheckReleaseChanges();
+
+                if (ShouldCallReleaseCallback)
+                {
+                    ShouldCallReleaseCallback = false;
+
+                    Callback();
+                }
+            }
+
+            private void CheckReleaseChanges()
+            {
+                AL.GetSource(SourceId, ALGetSourcei.BuffersProcessed, out int ReleasedCount);
+
+                CheckReleaseChanges(ReleasedCount);
+            }
+
+            private void CheckReleaseChanges(int NewReleasedCount)
+            {
+                if (LastReleasedCount != NewReleasedCount)
+                {
+                    LastReleasedCount = NewReleasedCount;
+
+                    ShouldCallReleaseCallback = true;
+                }
+            }
             
             private void SyncQueuedTags()
             {
@@ -156,18 +195,46 @@ namespace Ryujinx.Audio.OpenAL
 
         private ConcurrentDictionary<int, Track> Tracks;
 
+        private Thread AudioPollerThread;
+
+        private bool KeepPolling;
+
         public OpenALAudioOut()
         {
             Context = new AudioContext();
 
             Tracks = new ConcurrentDictionary<int, Track>();
+
+            KeepPolling = true;
+
+            AudioPollerThread = new Thread(AudioPollerWork);
+
+            AudioPollerThread.Start();
+        }
+
+        private void AudioPollerWork()
+        {
+            do
+            {
+                foreach (Track Td in Tracks.Values)
+                {
+                    Td.CallReleaseCallbackIfNeeded();
+                }
+
+                Thread.Yield();
+            }
+            while (KeepPolling);
         }
 
-        public int OpenTrack(int SampleRate, int Channels, out AudioFormat Format)
+        public int OpenTrack(
+            int             SampleRate,
+            int             Channels,
+            ReleaseCallback Callback,
+            out AudioFormat Format)
         {
             Format = AudioFormat.PcmInt16;
 
-            Track Td = new Track(SampleRate, GetALFormat(Channels, Format));
+            Track Td = new Track(SampleRate, GetALFormat(Channels, Format), Callback);
 
             for (int Id = 0; Id < MaxTracks; Id++)
             {
@@ -292,5 +359,7 @@ namespace Ryujinx.Audio.OpenAL
 
             return PlaybackState.Stopped;
         }
+
+
     }
 }

+ 4 - 0
Ryujinx.Audio/ReleaseCallback.cs

@@ -0,0 +1,4 @@
+namespace Ryujinx.Audio
+{
+    public delegate void ReleaseCallback();
+}

+ 62 - 0
Ryujinx.Core/OsHle/AppletStateMgr.cs

@@ -0,0 +1,62 @@
+using Ryujinx.Core.OsHle.IpcServices.Am;
+using Ryujinx.Core.OsHle.Handles;
+using System;
+using System.Collections.Concurrent;
+
+namespace Ryujinx.Core.OsHle
+{
+    class AppletStateMgr : IDisposable
+    {
+        private ConcurrentQueue<MessageInfo> Messages;
+
+        public FocusState FocusState { get; private set; }
+
+        public KEvent MessageEvent { get; private set; }
+
+        public AppletStateMgr()
+        {
+            Messages = new ConcurrentQueue<MessageInfo>();
+
+            MessageEvent = new KEvent();
+        }
+
+        public void SetFocus(bool IsFocused)
+        {
+            FocusState = IsFocused 
+                ? FocusState.InFocus
+                : FocusState.OutOfFocus;
+
+            EnqueueMessage(MessageInfo.FocusStateChanged);
+        }
+
+        public void EnqueueMessage(MessageInfo Message)
+        {
+            Messages.Enqueue(Message);
+
+            MessageEvent.Handle.Set();
+        }
+
+        public bool TryDequeueMessage(out MessageInfo Message)
+        {
+            if (Messages.Count < 2)
+            {
+                MessageEvent.Handle.Reset();
+            }
+
+            return Messages.TryDequeue(out Message);
+        }
+
+        public void Dispose()
+        {
+            Dispose(true);
+        }
+
+        protected virtual void Dispose(bool Disposing)
+        {
+            if (Disposing)
+            {
+                MessageEvent.Dispose();
+            }
+        }
+    }
+}

+ 4 - 4
Ryujinx.Core/OsHle/CondVar.cs

@@ -13,7 +13,7 @@ namespace Ryujinx.Core.OsHle
 
         private bool OwnsCondVarValue;
 
-        private List<HThread> WaitingThreads;
+        private List<KThread> WaitingThreads;
 
         public CondVar(Process Process, long CondVarAddress, long Timeout)
         {
@@ -21,10 +21,10 @@ namespace Ryujinx.Core.OsHle
             this.CondVarAddress = CondVarAddress;
             this.Timeout        = Timeout;
 
-            WaitingThreads = new List<HThread>();
+            WaitingThreads = new List<KThread>();
         }
 
-        public bool WaitForSignal(HThread Thread)
+        public bool WaitForSignal(KThread Thread)
         {
             int Count = Process.Memory.ReadInt32(CondVarAddress);
 
@@ -66,7 +66,7 @@ namespace Ryujinx.Core.OsHle
             return true;
         }
 
-        public void SetSignal(HThread Thread, int Count)
+        public void SetSignal(KThread Thread, int Count)
         {
             lock (WaitingThreads)
             {

+ 0 - 12
Ryujinx.Core/OsHle/FileDesc.cs

@@ -1,12 +0,0 @@
-namespace Ryujinx.Core.OsHle
-{
-    class FileDesc
-    {
-        public string Name { get; private set; }
-
-        public FileDesc(string Name)
-        {
-            this.Name = Name;
-        }
-    }
-}

+ 62 - 0
Ryujinx.Core/OsHle/GlobalStateTable.cs

@@ -0,0 +1,62 @@
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+
+namespace Ryujinx.Core.OsHle
+{
+    class GlobalStateTable
+    {
+        private ConcurrentDictionary<Process, IdDictionary> DictByProcess;
+
+        public GlobalStateTable()
+        {
+            DictByProcess = new ConcurrentDictionary<Process, IdDictionary>();
+        }
+
+        public int Add(Process Process, object Obj)
+        {
+            IdDictionary Dict = DictByProcess.GetOrAdd(Process, (Key) => new IdDictionary());
+
+            return Dict.Add(Obj);
+        }
+
+        public object GetData(Process Process, int Id)
+        {
+            if (DictByProcess.TryGetValue(Process, out IdDictionary Dict))
+            {
+                return Dict.GetData(Id);
+            }
+
+            return null;
+        }
+
+        public T GetData<T>(Process Process, int Id)
+        {
+            if (DictByProcess.TryGetValue(Process, out IdDictionary Dict))
+            {
+                return Dict.GetData<T>(Id);
+            }
+
+            return default(T);
+        }
+
+        public object Delete(Process Process, int Id)
+        {
+            if (DictByProcess.TryGetValue(Process, out IdDictionary Dict))
+            {
+                return Dict.Delete(Id);
+            }
+
+            return null;
+        }
+
+        public ICollection<object> DeleteProcess(Process Process)
+        {
+            if (DictByProcess.TryRemove(Process, out IdDictionary Dict))
+            {
+                return Dict.Clear();
+            }
+
+            return null;
+        }
+    }
+}

+ 0 - 48
Ryujinx.Core/OsHle/Handles/HDomain.cs

@@ -1,48 +0,0 @@
-using System;
-
-namespace Ryujinx.Core.OsHle.Handles
-{
-    class HDomain : HSession, IDisposable
-    {
-        private IdDictionary Objects;
-
-        public HDomain(HSession Session) : base(Session)
-        {
-            Objects = new IdDictionary();
-        }
-
-        public int Add(object Obj)
-        {
-            return Objects.Add(Obj);
-        }
-
-        public bool Delete(int Id)
-        {
-            return Objects.Delete(Id);
-        }
-
-        public object GetObject(int Id)
-        {
-            return Objects.GetData(Id);
-        }
-
-        public void Dispose()
-        {
-            Dispose(true);
-        }
-
-        protected virtual void Dispose(bool Disposing)
-        {
-            if (Disposing)
-            {
-                foreach (object Obj in Objects)
-                {
-                    if (Obj != this && Obj is IDisposable DisposableObj)
-                    {
-                        DisposableObj.Dispose();
-                    }
-                }
-            }
-        }
-    }
-}

+ 0 - 7
Ryujinx.Core/OsHle/Handles/HEvent.cs

@@ -1,7 +0,0 @@
-namespace Ryujinx.Core.OsHle.Handles
-{
-    class HEvent
-    {
-
-    }
-}

+ 0 - 29
Ryujinx.Core/OsHle/Handles/HSession.cs

@@ -1,29 +0,0 @@
-using Ryujinx.Core.OsHle.IpcServices;
-
-namespace Ryujinx.Core.OsHle.Handles
-{
-    class HSession
-    {
-        public IIpcService Service { get; private set; }
-
-        public bool IsInitialized { get; private set; }
-
-        public int State { get; set; }
-
-        public HSession(IIpcService Service)
-        {
-            this.Service = Service;
-        }
-
-        public HSession(HSession Session)
-        {
-            Service       = Session.Service;
-            IsInitialized = Session.IsInitialized;
-        }
-
-        public void Initialize()
-        {
-            IsInitialized = true;
-        }
-    }
-}

+ 0 - 30
Ryujinx.Core/OsHle/Handles/HSessionObj.cs

@@ -1,30 +0,0 @@
-using System;
-
-namespace Ryujinx.Core.OsHle.Handles
-{
-    class HSessionObj : HSession, IDisposable
-    {
-        public object Obj { get; private set; }
-
-        public HSessionObj(HSession Session, object Obj) : base(Session)
-        {
-            this.Obj = Obj;
-        }
-
-        public void Dispose()
-        {
-            Dispose(true);
-        }
-
-        protected virtual void Dispose(bool Disposing)
-        {
-            if (Disposing && Obj != null)
-            {
-                if (Obj is IDisposable DisposableObj)
-                {
-                    DisposableObj.Dispose();
-                }
-            }
-        }
-    }
-}

+ 4 - 0
Ryujinx.Core/OsHle/Handles/KEvent.cs

@@ -0,0 +1,4 @@
+namespace Ryujinx.Core.OsHle.Handles
+{
+    class KEvent : KSynchronizationObject { }
+}

+ 5 - 34
Ryujinx.Core/OsHle/Handles/KProcessHandleTable.cs

@@ -1,8 +1,8 @@
-using System;
+using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.Handles
 {
-    class KProcessHandleTable : IDisposable
+    class KProcessHandleTable
     {
         private IdDictionary Handles;
 
@@ -21,43 +21,14 @@ namespace Ryujinx.Core.OsHle.Handles
             return Handles.GetData<T>(Handle);
         }
 
-        public bool ReplaceData(int Id, object Data)
+        public object CloseHandle(int Handle)
         {
-            return Handles.ReplaceData(Id, Data);
-        }
-
-        public bool CloseHandle(int Handle)
-        {
-            object Data = Handles.GetData(Handle);
-
-            if (Data is HTransferMem TMem)
-            {
-                TMem.Memory.Manager.Reprotect(
-                    TMem.Position,
-                    TMem.Size,
-                    TMem.Perm);
-            }
-
             return Handles.Delete(Handle);
         }
 
-        public void Dispose()
-        {
-            Dispose(true);
-        }
-
-        protected virtual void Dispose(bool Disposing)
+        public ICollection<object> Clear()
         {
-            if (Disposing)
-            {
-                foreach (object Obj in Handles)
-                {
-                    if (Obj is IDisposable DisposableObj)
-                    {
-                        DisposableObj.Dispose();
-                    }
-                }
-            }
+            return Handles.Clear();
         }
     }
 }

+ 13 - 13
Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs

@@ -5,15 +5,15 @@ using System.Threading;
 
 namespace Ryujinx.Core.OsHle.Handles
 {
-    public class KProcessScheduler : IDisposable
+    class KProcessScheduler : IDisposable
     {
         private class SchedulerThread : IDisposable
         {
-            public HThread Thread { get; private set; }
+            public KThread Thread { get; private set; }
 
             public AutoResetEvent WaitEvent { get; private set; }
 
-            public SchedulerThread(HThread Thread)
+            public SchedulerThread(KThread Thread)
             {
                 this.Thread = Thread;
 
@@ -95,7 +95,7 @@ namespace Ryujinx.Core.OsHle.Handles
             }
         }
 
-        private ConcurrentDictionary<HThread, SchedulerThread> AllThreads;
+        private ConcurrentDictionary<KThread, SchedulerThread> AllThreads;
 
         private ThreadQueue[] WaitingToRun;
 
@@ -105,7 +105,7 @@ namespace Ryujinx.Core.OsHle.Handles
 
         public KProcessScheduler()
         {
-            AllThreads = new ConcurrentDictionary<HThread, SchedulerThread>();
+            AllThreads = new ConcurrentDictionary<KThread, SchedulerThread>();
 
             WaitingToRun = new ThreadQueue[4];
 
@@ -119,7 +119,7 @@ namespace Ryujinx.Core.OsHle.Handles
             SchedLock = new object();
         }
 
-        public void StartThread(HThread Thread)
+        public void StartThread(KThread Thread)
         {
             lock (SchedLock)
             {
@@ -164,7 +164,7 @@ namespace Ryujinx.Core.OsHle.Handles
             }
         }
 
-        public void Resume(HThread CurrThread)
+        public void Resume(KThread CurrThread)
         {
             SchedulerThread SchedThread;
 
@@ -183,7 +183,7 @@ namespace Ryujinx.Core.OsHle.Handles
             TryResumingExecution(SchedThread);
         }
 
-        public bool WaitForSignal(HThread Thread, int Timeout = -1)
+        public bool WaitForSignal(KThread Thread, int Timeout = -1)
         {
             SchedulerThread SchedThread;
 
@@ -230,7 +230,7 @@ namespace Ryujinx.Core.OsHle.Handles
 
         private void TryResumingExecution(SchedulerThread SchedThread)
         {
-            HThread Thread = SchedThread.Thread;
+            KThread Thread = SchedThread.Thread;
 
             lock (SchedLock)
             {
@@ -249,7 +249,7 @@ namespace Ryujinx.Core.OsHle.Handles
             Logging.Debug($"{GetDbgThreadInfo(Thread)} resuming execution...");
         }
 
-        public void Yield(HThread Thread)
+        public void Yield(KThread Thread)
         {
             SchedulerThread SchedThread;
 
@@ -295,11 +295,11 @@ namespace Ryujinx.Core.OsHle.Handles
             }
         }
 
-        public void Signal(params HThread[] Threads)
+        public void Signal(params KThread[] Threads)
         {
             lock (SchedLock)
             {
-                foreach (HThread Thread in Threads)
+                foreach (KThread Thread in Threads)
                 {
                     if (AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread))
                     {
@@ -314,7 +314,7 @@ namespace Ryujinx.Core.OsHle.Handles
             }
         }
 
-        private string GetDbgThreadInfo(HThread Thread)
+        private string GetDbgThreadInfo(KThread Thread)
         {
             return $"Thread {Thread.ThreadId} (core {Thread.ProcessorId}) prio {Thread.Priority}";
         }

+ 28 - 0
Ryujinx.Core/OsHle/Handles/KSession.cs

@@ -0,0 +1,28 @@
+using Ryujinx.Core.OsHle.IpcServices;
+using System;
+
+namespace Ryujinx.Core.OsHle.Handles
+{
+    class KSession : IDisposable
+    {
+        public IpcService Service { get; private set; }
+
+        public KSession(IpcService Service)
+        {
+            this.Service = Service;
+        }
+
+        public void Dispose()
+        {
+            Dispose(true);
+        }
+
+        protected virtual void Dispose(bool Disposing)
+        {
+            if (Disposing && Service is IDisposable DisposableService)
+            {
+                DisposableService.Dispose();
+            }
+        }
+    }
+}

+ 28 - 0
Ryujinx.Core/OsHle/Handles/KSynchronizationObject.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Threading;
+
+namespace Ryujinx.Core.OsHle.Handles
+{
+    class KSynchronizationObject : IDisposable
+    {
+        public ManualResetEvent Handle { get; private set; }
+
+        public KSynchronizationObject()
+        {
+            Handle = new ManualResetEvent(false);
+        }
+
+        public void Dispose()
+        {
+            Dispose(true);
+        }
+
+        protected virtual void Dispose(bool Disposing)
+        {
+            if (Disposing)
+            {
+                Handle.Dispose();
+            }
+        }
+    }
+}

+ 2 - 2
Ryujinx.Core/OsHle/Handles/HThread.cs → Ryujinx.Core/OsHle/Handles/KThread.cs

@@ -2,7 +2,7 @@ using ChocolArm64;
 
 namespace Ryujinx.Core.OsHle.Handles
 {
-    public class HThread
+    class KThread : KSynchronizationObject
     {
         public AThread Thread { get; private set; }
 
@@ -11,7 +11,7 @@ namespace Ryujinx.Core.OsHle.Handles
 
         public int ThreadId => Thread.ThreadId;
 
-        public HThread(AThread Thread, int ProcessorId, int Priority)
+        public KThread(AThread Thread, int ProcessorId, int Priority)
         {
             this.Thread      = Thread;
             this.ProcessorId = ProcessorId;

+ 17 - 2
Ryujinx.Core/OsHle/Horizon.cs

@@ -16,8 +16,10 @@ namespace Ryujinx.Core.OsHle
 
         private ConcurrentDictionary<int, Process> Processes;
 
-        internal HSharedMem HidSharedMem;
-        internal HSharedMem FontSharedMem;
+        internal HSharedMem HidSharedMem  { get; private set; }
+        internal HSharedMem FontSharedMem { get; private set; }
+
+        internal KEvent VsyncEvent { get; private set; }
 
         private Switch Ns;
 
@@ -32,6 +34,8 @@ namespace Ryujinx.Core.OsHle
 
             HidSharedMem  = new HSharedMem();
             FontSharedMem = new HSharedMem();
+
+            VsyncEvent = new KEvent();
         }
 
         public void LoadCart(string ExeFsDir, string RomFsFile = null)
@@ -91,6 +95,8 @@ namespace Ryujinx.Core.OsHle
             MainProcess.Run(IsNro);
         }
 
+        public void SignalVsync() => VsyncEvent.Handle.Set();
+
         private Process MakeProcess()
         {
             Process Process;
@@ -109,9 +115,16 @@ namespace Ryujinx.Core.OsHle
                 Processes.TryAdd(ProcessId, Process);
             }
 
+            InitializeProcess(Process);
+
             return Process;
         }
 
+        private void InitializeProcess(Process Process)
+        {
+            Process.AppletState.SetFocus(true);
+        }
+
         internal void ExitProcess(int ProcessId)
         {
             if (Processes.TryGetValue(ProcessId, out Process Process) && Process.NeedsHbAbi)
@@ -171,6 +184,8 @@ namespace Ryujinx.Core.OsHle
                     Process.StopAllThreadsAsync();
                     Process.Dispose();
                 }
+
+                VsyncEvent.Dispose();
             }
         }
     }

+ 9 - 28
Ryujinx.Core/OsHle/IdDictionary.cs

@@ -1,11 +1,10 @@
 using System;
-using System.Collections;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle
 {
-    class IdDictionary : IEnumerable<object>
+    class IdDictionary
     {
         private ConcurrentDictionary<int, object> Objs;
 
@@ -39,18 +38,6 @@ namespace Ryujinx.Core.OsHle
             throw new InvalidOperationException();
         }
 
-        public bool ReplaceData(int Id, object Data)
-        {
-            if (Objs.ContainsKey(Id))
-            {
-                Objs[Id] = Data;
-
-                return true;
-            }
-
-            return false;
-        }
-
         public object GetData(int Id)
         {
             if (Objs.TryGetValue(Id, out object Data))
@@ -71,31 +58,25 @@ namespace Ryujinx.Core.OsHle
             return default(T);
         }
 
-        public bool Delete(int Id)
+        public object Delete(int Id)
         {
             if (Objs.TryRemove(Id, out object Obj))
             {
-                if (Obj is IDisposable DisposableObj)
-                {
-                    DisposableObj.Dispose();
-                }
-
                 FreeIdHint = Id;
 
-                return true;
+                return Obj;
             }
 
-            return false;
+            return null;
         }
 
-        IEnumerator<object> IEnumerable<object>.GetEnumerator()
+        public ICollection<object> Clear()
         {
-            return Objs.Values.GetEnumerator();
-        }
+            ICollection<object> Values = Objs.Values;
 
-        IEnumerator IEnumerable.GetEnumerator()
-        {
-            return Objs.Values.GetEnumerator();
+            Objs.Clear();
+
+            return Values;
         }
     }
 }

+ 0 - 8
Ryujinx.Core/OsHle/Ipc/IpcDomCmd.cs

@@ -1,8 +0,0 @@
-namespace Ryujinx.Core.OsHle.Ipc
-{
-    enum IpcDomCmd
-    {
-        SendMsg   = 1,
-        DeleteObj = 2
-    }
-}

+ 19 - 98
Ryujinx.Core/OsHle/Ipc/IpcHandler.cs

@@ -1,6 +1,5 @@
 using ChocolArm64.Memory;
 using Ryujinx.Core.OsHle.Handles;
-using Ryujinx.Core.OsHle.IpcServices;
 using System;
 using System.IO;
 
@@ -8,20 +7,15 @@ namespace Ryujinx.Core.OsHle.Ipc
 {
     static class IpcHandler
     {
-        private const long SfciMagic = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'I' << 24;
-        private const long SfcoMagic = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'O' << 24;
-
         public static void IpcCall(
             Switch     Ns,
             Process    Process,
             AMemory    Memory,
-            HSession   Session,
+            KSession   Session,
             IpcMessage Request,
-            int        ThreadId,
-            long       CmdPtr,
-            int        HndId)
+            long       CmdPtr)
         {
-            IpcMessage Response = new IpcMessage(Request.IsDomain && Request.Type == IpcMessageType.Request);
+            IpcMessage Response = new IpcMessage();
 
             using (MemoryStream Raw = new MemoryStream(Request.RawData))
             {
@@ -29,94 +23,25 @@ namespace Ryujinx.Core.OsHle.Ipc
 
                 if (Request.Type == IpcMessageType.Request)
                 {
-                    string ServiceName = Session.Service.GetType().Name;
-
-                    ServiceProcessRequest ProcReq = null;
-
-                    bool IgnoreNullPR = false;
-
-                    string DbgServiceName = string.Empty;
-
-                    if (Session is HDomain Dom)
-                    {
-                        if (Request.DomCmd == IpcDomCmd.SendMsg)
-                        {
-                            long Magic =      ReqReader.ReadInt64();
-                            int  CmdId = (int)ReqReader.ReadInt64();
-
-                            object Obj = Dom.GetObject(Request.DomObjId);
-
-                            if (Obj is HDomain)
-                            {
-                                Session.Service.Commands.TryGetValue(CmdId, out ProcReq);
-
-                                DbgServiceName = $"{ProcReq?.Method.Name ?? CmdId.ToString()}";
-                            }
-                            else if (Obj != null)
-                            {
-                                ((IIpcService)Obj).Commands.TryGetValue(CmdId, out ProcReq);
-
-                                DbgServiceName = $"{Obj.GetType().Name} {ProcReq?.Method.Name ?? CmdId.ToString()}";
-                            }
-                        }
-                        else if (Request.DomCmd == IpcDomCmd.DeleteObj)
-                        {
-                            Dom.Delete(Request.DomObjId);
-
-                            Response = FillResponse(Response, 0);
-
-                            IgnoreNullPR = true;
-                        }
-                    }
-                    else
-                    {
-                        long Magic =      ReqReader.ReadInt64();
-                        int  CmdId = (int)ReqReader.ReadInt64();
-
-                        if (Session is HSessionObj)
-                        {
-                            object Obj = ((HSessionObj)Session).Obj;
+                    Response.Type = IpcMessageType.Response;
 
-                            ((IIpcService)Obj).Commands.TryGetValue(CmdId, out ProcReq);
-
-                            DbgServiceName = $"{Obj.GetType().Name} {ProcReq?.Method.Name ?? CmdId.ToString()}";
-                        }
-                        else
-                        {
-                            Session.Service.Commands.TryGetValue(CmdId, out ProcReq);
-
-                            DbgServiceName = $"{ProcReq?.Method.Name ?? CmdId.ToString()}";
-                        }
-                    }
-
-                    DbgServiceName = $"Tid {ThreadId} {ServiceName} {DbgServiceName}";
-
-                    Logging.Debug($"IpcMessage: {DbgServiceName}");
-
-                    if (ProcReq != null)
+                    using (MemoryStream ResMS = new MemoryStream())
                     {
-                        using (MemoryStream ResMS = new MemoryStream())
-                        {
-                            BinaryWriter ResWriter = new BinaryWriter(ResMS);
+                        BinaryWriter ResWriter = new BinaryWriter(ResMS);
 
-                            ServiceCtx Context = new ServiceCtx(
-                                Ns,
-                                Process,
-                                Memory,
-                                Session,
-                                Request,
-                                Response,
-                                ReqReader,
-                                ResWriter);
+                        ServiceCtx Context = new ServiceCtx(
+                            Ns,
+                            Process,
+                            Memory,
+                            Session,
+                            Request,
+                            Response,
+                            ReqReader,
+                            ResWriter);
 
-                            long Result = ProcReq(Context);
+                        Session.Service.CallMethod(Context);
 
-                            Response = FillResponse(Response, Result, ResMS.ToArray());
-                        }
-                    }
-                    else if (!IgnoreNullPR)
-                    {   
-                        throw new NotImplementedException(DbgServiceName);
+                        Response.RawData = ResMS.ToArray();
                     }
                 }
                 else if (Request.Type == IpcMessageType.Control)
@@ -128,11 +53,7 @@ namespace Ryujinx.Core.OsHle.Ipc
                     {
                         case 0:
                         {
-                            HDomain Dom = new HDomain(Session);
-
-                            Process.HandleTable.ReplaceData(HndId, Dom);
-
-                            Request = FillResponse(Response, 0, Dom.Add(Dom));
+                            Request = FillResponse(Response, 0, Session.Service.ConvertToDomain());
 
                             break;
                         }
@@ -198,7 +119,7 @@ namespace Ryujinx.Core.OsHle.Ipc
             {
                 BinaryWriter Writer = new BinaryWriter(MS);
 
-                Writer.Write(SfcoMagic);
+                Writer.Write(IpcMagic.Sfco);
                 Writer.Write(Result);
 
                 if (Data != null)

+ 1 - 2
Ryujinx.Core/OsHle/Ipc/IpcLog.cs

@@ -125,8 +125,7 @@ namespace Ryujinx.Core.OsHle.Ipc
 
                     Reader.ReadInt64(); //Padding
 
-                    IpcMessage += Environment.NewLine + $"    Domain:" + Environment.NewLine +
-                                  $"      DomCmd: {Enum.GetName(typeof(IpcDomCmd), DomCmd)}" + Environment.NewLine +
+                    IpcMessage += Environment.NewLine + $"    Domain:" + Environment.NewLine + Environment.NewLine +
                                   $"      DomObjId: {DomObjId.ToString()}" + Environment.NewLine;
                 }
 

+ 8 - 0
Ryujinx.Core/OsHle/Ipc/IpcMagic.cs

@@ -0,0 +1,8 @@
+namespace Ryujinx.Core.OsHle.Ipc
+{
+    abstract class IpcMagic
+    {
+        public const long Sfci = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'I' << 24;
+        public const long Sfco = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'O' << 24;
+    }
+}

+ 4 - 44
Ryujinx.Core/OsHle/Ipc/IpcMessage.cs

@@ -17,10 +17,6 @@ namespace Ryujinx.Core.OsHle.Ipc
 
         public List<int> ResponseObjIds { get; private set; }    
 
-        public bool      IsDomain { get; private set; }
-        public IpcDomCmd DomCmd   { get; private set; }
-        public int       DomObjId { get; private set; }
-
         public byte[] RawData { get; set; }
 
         public IpcMessage()
@@ -34,27 +30,18 @@ namespace Ryujinx.Core.OsHle.Ipc
             ResponseObjIds = new List<int>();
         }
 
-        public IpcMessage(bool Domain) : this()
+        public IpcMessage(byte[] Data, long CmdPtr) : this()
         {
-            IsDomain = Domain;
-        }
-
-        public IpcMessage(byte[] Data, long CmdPtr, bool Domain) : this()
-        {
-            Logging.Ipc(Data, CmdPtr, Domain);
-
             using (MemoryStream MS = new MemoryStream(Data))
             {
                 BinaryReader Reader = new BinaryReader(MS);
 
-                Initialize(Reader, CmdPtr, Domain);
+                Initialize(Reader, CmdPtr);
             }
         }
 
-        private void Initialize(BinaryReader Reader, long CmdPtr, bool Domain)
+        private void Initialize(BinaryReader Reader, long CmdPtr)
         {
-            IsDomain = Domain;
-
             int Word0 = Reader.ReadInt32();
             int Word1 = Reader.ReadInt32();
 
@@ -110,19 +97,6 @@ namespace Ryujinx.Core.OsHle.Ipc
                 RecvListCount = 0;
             }
 
-            if (Domain && Type == IpcMessageType.Request)
-            {
-                int DomWord0 = Reader.ReadInt32();
-
-                DomCmd = (IpcDomCmd)(DomWord0 & 0xff);
-
-                RawDataSize = (DomWord0 >> 16) & 0xffff;
-
-                DomObjId = Reader.ReadInt32();
-
-                Reader.ReadInt64(); //Padding
-            }
-
             RawData = Reader.ReadBytes(RawDataSize);
 
             Reader.BaseStream.Seek(RecvListPos, SeekOrigin.Begin);
@@ -165,9 +139,7 @@ namespace Ryujinx.Core.OsHle.Ipc
                 //This is the weirdest padding I've seen so far...
                 int Pad1 = 0x10 - Pad0;
 
-                DataLength = (DataLength + Pad0 + Pad1 + (IsDomain ? 0x10 : 0)) / 4;
-
-                DataLength += ResponseObjIds.Count;
+                DataLength = (DataLength + Pad0 + Pad1) / 4;
 
                 Word1 = DataLength & 0x3ff;
 
@@ -182,23 +154,11 @@ namespace Ryujinx.Core.OsHle.Ipc
 
                 MS.Seek(Pad0, SeekOrigin.Current);
 
-                if (IsDomain)
-                {
-                    Writer.Write(ResponseObjIds.Count);
-                    Writer.Write(0);
-                    Writer.Write(0L);
-                }
-
                 if (RawData != null)
                 {
                     Writer.Write(RawData);
                 }
 
-                foreach (int Id in ResponseObjIds)
-                {
-                    Writer.Write(Id);
-                }
-
                 Writer.Write(new byte[Pad1]);
 
                 return MS.ToArray();

+ 0 - 1
Ryujinx.Core/OsHle/KernelErr.cs

@@ -6,6 +6,5 @@ namespace Ryujinx.Core.OsHle
         public const int InvalidHandle   = 114;
         public const int Timeout         = 117;
         public const int InvalidInfo     = 120;
-        public const int InvalidIpcReq   = 123;
     }
 }

+ 5 - 5
Ryujinx.Core/OsHle/Mutex.cs

@@ -16,7 +16,7 @@ namespace Ryujinx.Core.OsHle
 
         private object EnterWaitLock;
 
-        private ConcurrentQueue<HThread> WaitingThreads;
+        private ConcurrentQueue<KThread> WaitingThreads;
 
         public Mutex(Process Process, long MutexAddress, int OwnerThreadHandle)
         {
@@ -27,10 +27,10 @@ namespace Ryujinx.Core.OsHle
 
             EnterWaitLock = new object();
 
-            WaitingThreads = new ConcurrentQueue<HThread>();
+            WaitingThreads = new ConcurrentQueue<KThread>();
         }
 
-        public void WaitForLock(HThread RequestingThread, int RequestingThreadHandle)
+        public void WaitForLock(KThread RequestingThread, int RequestingThreadHandle)
         {
             AcquireMutexValue();
 
@@ -83,11 +83,11 @@ namespace Ryujinx.Core.OsHle
 
                 ReleaseMutexValue();
 
-                HThread[] UnlockedThreads = new HThread[WaitingThreads.Count];
+                KThread[] UnlockedThreads = new KThread[WaitingThreads.Count];
 
                 int Index = 0;
 
-                while (WaitingThreads.TryDequeue(out HThread Thread))
+                while (WaitingThreads.TryDequeue(out KThread Thread))
                 {
                     UnlockedThreads[Index++] = Thread;
                 }

+ 32 - 15
Ryujinx.Core/OsHle/Process.cs

@@ -5,6 +5,7 @@ using Ryujinx.Core.Loaders;
 using Ryujinx.Core.Loaders.Executables;
 using Ryujinx.Core.OsHle.Exceptions;
 using Ryujinx.Core.OsHle.Handles;
+using Ryujinx.Core.OsHle.IpcServices.NvServices;
 using Ryujinx.Core.OsHle.Svc;
 using System;
 using System.Collections.Concurrent;
@@ -31,21 +32,21 @@ namespace Ryujinx.Core.OsHle
 
         public AMemory Memory { get; private set; }
 
-        public ServiceMgr Services { get; private set; }
-
         public KProcessScheduler Scheduler { get; private set; }
 
         public KProcessHandleTable HandleTable { get; private set; }
 
+        public AppletStateMgr AppletState { get; private set; }
+
         private SvcHandler SvcHandler;
 
         private ConcurrentDictionary<int, AThread> TlsSlots;
 
-        private ConcurrentDictionary<long, HThread> ThreadsByTpidr;
+        private ConcurrentDictionary<long, KThread> ThreadsByTpidr;
 
         private List<Executable> Executables;
 
-        private HThread MainThread;
+        private KThread MainThread;
 
         private long ImageBase;
 
@@ -60,17 +61,17 @@ namespace Ryujinx.Core.OsHle
 
             Memory = new AMemory();
 
-            Services = new ServiceMgr();
-
             HandleTable = new KProcessHandleTable();
 
-            Scheduler = new KProcessScheduler();            
+            Scheduler = new KProcessScheduler();
+
+            AppletState = new AppletStateMgr();
 
             SvcHandler = new SvcHandler(Ns, this);
 
             TlsSlots = new ConcurrentDictionary<int, AThread>();
 
-            ThreadsByTpidr = new ConcurrentDictionary<long, HThread>();
+            ThreadsByTpidr = new ConcurrentDictionary<long, KThread>();
 
             Executables = new List<Executable>();
 
@@ -132,7 +133,7 @@ namespace Ryujinx.Core.OsHle
                 return false;
             }
 
-            MainThread = HandleTable.GetData<HThread>(Handle);
+            MainThread = HandleTable.GetData<KThread>(Handle);
 
             if (NeedsHbAbi)
             {
@@ -186,7 +187,7 @@ namespace Ryujinx.Core.OsHle
 
             AThread Thread = new AThread(GetTranslator(), Memory, EntryPoint);
 
-            HThread ThreadHnd = new HThread(Thread, ProcessorId, Priority);
+            KThread ThreadHnd = new KThread(Thread, ProcessorId, Priority);
 
             int Handle = HandleTable.OpenHandle(ThreadHnd);
 
@@ -311,9 +312,9 @@ namespace Ryujinx.Core.OsHle
             return (int)((Position - MemoryRegions.TlsPagesAddress) / TlsSize);
         }
 
-        public HThread GetThread(long Tpidr)
+        public KThread GetThread(long Tpidr)
         {
-            if (!ThreadsByTpidr.TryGetValue(Tpidr, out HThread Thread))
+            if (!ThreadsByTpidr.TryGetValue(Tpidr, out KThread Thread))
             {
                 Logging.Error($"Thread with TPIDR 0x{Tpidr:x16} not found!");
             }
@@ -344,11 +345,27 @@ namespace Ryujinx.Core.OsHle
                 }
 
                 Disposed = true;
-                
-                Services.Dispose();
-                HandleTable.Dispose();
+
+                foreach (object Obj in HandleTable.Clear())
+                {
+                    if (Obj is KSession Session)
+                    {
+                        Session.Dispose();
+                    }
+                }
+
+                ServiceNvDrv.Fds.DeleteProcess(this);
+
+                ServiceNvDrv.NvMaps.DeleteProcess(this);
+
+                ServiceNvDrv.NvMapsById.DeleteProcess(this);
+
                 Scheduler.Dispose();
+
+                AppletState.Dispose();
+
                 SvcHandler.Dispose();
+
                 Memory.Dispose();
 
                 Logging.Info($"Process {ProcessId} exiting...");

+ 2 - 2
Ryujinx.Core/OsHle/ServiceCtx.cs

@@ -10,7 +10,7 @@ namespace Ryujinx.Core.OsHle
         public Switch       Ns           { get; private set; }
         public Process      Process      { get; private set; }
         public AMemory      Memory       { get; private set; }
-        public HSession     Session      { get; private set; }
+        public KSession     Session      { get; private set; }
         public IpcMessage   Request      { get; private set; }
         public IpcMessage   Response     { get; private set; }
         public BinaryReader RequestData  { get; private set; }
@@ -20,7 +20,7 @@ namespace Ryujinx.Core.OsHle
             Switch       Ns,
             Process      Process,
             AMemory      Memory,
-            HSession     Session,
+            KSession     Session,
             IpcMessage   Request,
             IpcMessage   Response,
             BinaryReader RequestData,

+ 0 - 128
Ryujinx.Core/OsHle/ServiceMgr.cs

@@ -1,128 +0,0 @@
-using Ryujinx.Core.OsHle.IpcServices;
-using Ryujinx.Core.OsHle.IpcServices.Acc;
-using Ryujinx.Core.OsHle.IpcServices.Am;
-using Ryujinx.Core.OsHle.IpcServices.Apm;
-using Ryujinx.Core.OsHle.IpcServices.Aud;
-using Ryujinx.Core.OsHle.IpcServices.Bsd;
-using Ryujinx.Core.OsHle.IpcServices.Friend;
-using Ryujinx.Core.OsHle.IpcServices.FspSrv;
-using Ryujinx.Core.OsHle.IpcServices.Hid;
-using Ryujinx.Core.OsHle.IpcServices.Lm;
-using Ryujinx.Core.OsHle.IpcServices.Nifm;
-using Ryujinx.Core.OsHle.IpcServices.Ns;
-using Ryujinx.Core.OsHle.IpcServices.NvServices;
-using Ryujinx.Core.OsHle.IpcServices.Pctl;
-using Ryujinx.Core.OsHle.IpcServices.Pl;
-using Ryujinx.Core.OsHle.IpcServices.Set;
-using Ryujinx.Core.OsHle.IpcServices.Sfdnsres;
-using Ryujinx.Core.OsHle.IpcServices.Sm;
-using Ryujinx.Core.OsHle.IpcServices.Ssl;
-using Ryujinx.Core.OsHle.IpcServices.Time;
-using Ryujinx.Core.OsHle.IpcServices.Vi;
-using System;
-using System.Collections.Generic;
-
-namespace Ryujinx.Core.OsHle
-{
-    class ServiceMgr : IDisposable
-    {
-        private Dictionary<string, IIpcService> Services;
-
-        public ServiceMgr()
-        {
-            Services = new Dictionary<string, IIpcService>();
-        }
-
-        public IIpcService GetService(string Name)
-        {
-            lock (Services)
-            {
-                string LookUpName;
-
-                //Same service with different privileges.
-                if (Name.EndsWith(":a")  ||
-                    Name.EndsWith(":m")  ||
-                    Name.EndsWith(":s")  ||
-                    Name.EndsWith(":su") ||
-                    Name.EndsWith(":u")  ||
-                    Name.EndsWith(":u0") ||
-                    Name.EndsWith(":u1"))
-                {
-                    LookUpName = Name.Substring(0, Name.IndexOf(':'));
-                }
-                else
-                {
-                    LookUpName = Name;
-                }
-
-                if (!Services.TryGetValue(LookUpName, out IIpcService Service))
-                {
-                    switch (Name)
-                    {
-                        case "acc:u0":   Service = new ServiceAcc();      break;
-                        case "aoc:u":    Service = new ServiceNs();       break;
-                        case "apm":      Service = new ServiceApm();      break;
-                        case "apm:p":    Service = new ServiceApm();      break;
-                        case "appletOE": Service = new ServiceAppletOE(); break;
-                        case "audout:u": Service = new ServiceAudOut();   break;
-                        case "audren:u": Service = new ServiceAudRen();   break;
-                        case "bsd:s":    Service = new ServiceBsd();      break;
-                        case "bsd:u":    Service = new ServiceBsd();      break;
-                        case "friend:a": Service = new ServiceFriend();   break;
-                        case "fsp-srv":  Service = new ServiceFspSrv();   break;
-                        case "hid":      Service = new ServiceHid();      break;
-                        case "lm":       Service = new ServiceLm();       break;
-                        case "nifm:u":   Service = new ServiceNifm();     break;
-                        case "nvdrv":    Service = new ServiceNvDrv();    break;
-                        case "nvdrv:a":  Service = new ServiceNvDrv();    break;
-                        case "pctl:a":   Service = new ServicePctl();     break;
-                        case "pl:u":     Service = new ServicePl();       break;
-                        case "set":      Service = new ServiceSet();      break;
-                        case "set:sys":  Service = new ServiceSetSys();   break;
-                        case "sfdnsres": Service = new ServiceSfdnsres(); break;
-                        case "sm:":      Service = new ServiceSm();       break;
-                        case "ssl":      Service = new ServiceSsl();      break;
-                        case "time:s":   Service = new ServiceTime();     break;
-                        case "time:u":   Service = new ServiceTime();     break;
-                        case "vi:m":     Service = new ServiceVi();       break;
-                        case "vi:s":     Service = new ServiceVi();       break;
-                        case "vi:u":     Service = new ServiceVi();       break;
-                    }
-
-                    if (Service == null)
-                    {
-                        throw new NotImplementedException(Name);
-                    }
-
-                    Services.Add(LookUpName, Service);
-                }
-
-                return Service;
-            }
-        }
-
-        public void Dispose()
-        {
-            Dispose(true);
-        }
-
-        protected virtual void Dispose(bool Disposing)
-        {
-            if (Disposing)
-            {
-                lock (Services)
-                {
-                    foreach (IIpcService Service in Services.Values)
-                    {
-                        if (Service is IDisposable DisposableSrv)
-                        {
-                            DisposableSrv.Dispose();
-                        }
-                    }
-
-                    Services.Clear();
-                }
-            }
-        }
-    }
-}

+ 2 - 2
Ryujinx.Core/OsHle/Services/Acc/IManagerForApplication.cs

@@ -3,11 +3,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Acc
 {
-    class IManagerForApplication : IIpcService
+    class IManagerForApplication : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public IManagerForApplication()
         {

+ 2 - 2
Ryujinx.Core/OsHle/Services/Acc/IProfile.cs

@@ -3,11 +3,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Acc
 {
-    class IProfile : IIpcService
+    class IProfile : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public IProfile()
         {

+ 2 - 4
Ryujinx.Core/OsHle/Services/Acc/ServiceAcc.cs

@@ -1,15 +1,13 @@
 using Ryujinx.Core.OsHle.Ipc;
 using System.Collections.Generic;
 
-using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
-
 namespace Ryujinx.Core.OsHle.IpcServices.Acc
 {
-    class ServiceAcc : IIpcService
+    class ServiceAcc : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ServiceAcc()
         {

+ 7 - 0
Ryujinx.Core/OsHle/Services/Am/AmErr.cs

@@ -0,0 +1,7 @@
+namespace Ryujinx.Core.OsHle.IpcServices.Am
+{
+    static class AmErr
+    {
+        public const int NoMessages = 3;
+    }
+}

+ 8 - 0
Ryujinx.Core/OsHle/Services/Am/FocusState.cs

@@ -0,0 +1,8 @@
+namespace Ryujinx.Core.OsHle.IpcServices.Am
+{
+    enum FocusState
+    {
+        InFocus    = 1,
+        OutOfFocus = 2
+    }
+}

+ 2 - 4
Ryujinx.Core/OsHle/Services/Am/IApplicationFunctions.cs

@@ -2,15 +2,13 @@ using Ryujinx.Core.OsHle.Ipc;
 using System.Collections.Generic;
 using System.IO;
 
-using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
-
 namespace Ryujinx.Core.OsHle.IpcServices.Am
 {
-    class IApplicationFunctions : IIpcService
+    class IApplicationFunctions : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public IApplicationFunctions()
         {

+ 2 - 4
Ryujinx.Core/OsHle/Services/Am/IApplicationProxy.cs

@@ -1,15 +1,13 @@
 using Ryujinx.Core.OsHle.Ipc;
 using System.Collections.Generic;
 
-using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
-
 namespace Ryujinx.Core.OsHle.IpcServices.Am
 {
-    class IApplicationProxy : IIpcService
+    class IApplicationProxy : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public IApplicationProxy()
         {

+ 2 - 2
Ryujinx.Core/OsHle/Services/Am/IAudioController.cs

@@ -3,11 +3,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Am
 {
-    class IAudioController : IIpcService
+    class IAudioController : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public IAudioController()
         {

+ 18 - 21
Ryujinx.Core/OsHle/Services/Am/ICommonStateGetter.cs

@@ -1,13 +1,16 @@
+using Ryujinx.Core.OsHle.Handles;
 using Ryujinx.Core.OsHle.Ipc;
 using System.Collections.Generic;
 
+using static Ryujinx.Core.OsHle.ErrorCode;
+
 namespace Ryujinx.Core.OsHle.IpcServices.Am
 {
-    class ICommonStateGetter : IIpcService
+    class ICommonStateGetter : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ICommonStateGetter()
         {
@@ -17,37 +20,31 @@ namespace Ryujinx.Core.OsHle.IpcServices.Am
                 { 1, ReceiveMessage       },
                 { 5, GetOperationMode     },
                 { 6, GetPerformanceMode   },
-                { 9, GetCurrentFocusState },
+                { 9, GetCurrentFocusState }
             };
         }
 
-        private enum FocusState
+        public long GetEventHandle(ServiceCtx Context)
         {
-            InFocus    = 1,
-            OutOfFocus = 2
-        }
+            KEvent Event = Context.Process.AppletState.MessageEvent;
 
-        private enum OperationMode
-        {
-            Handheld = 0,
-            Docked   = 1
-        }
+            int Handle = Context.Process.HandleTable.OpenHandle(Event);
 
-        public long GetEventHandle(ServiceCtx Context)
-        {
-            Context.ResponseData.Write(0L);
+            Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
             return 0;
         }
 
         public long ReceiveMessage(ServiceCtx Context)
         {
-            //Program expects 0xF at 0x17ae70 on puyo sdk,
-            //otherwise runs on a infinite loop until it reads said value.
-            //What it means is still unknown.
-            Context.ResponseData.Write(0xfL);
+            if (!Context.Process.AppletState.TryDequeueMessage(out MessageInfo Message))
+            {
+                return MakeError(ErrorModule.Am, AmErr.NoMessages);
+            }
 
-            return 0; //0x680;
+            Context.ResponseData.Write((int)Message);
+
+            return 0;
         }
 
         public long GetOperationMode(ServiceCtx Context)
@@ -66,7 +63,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Am
 
         public long GetCurrentFocusState(ServiceCtx Context)
         {
-            Context.ResponseData.Write((byte)FocusState.InFocus);
+            Context.ResponseData.Write((byte)Context.Process.AppletState.FocusState);
 
             return 0;
         }

+ 2 - 2
Ryujinx.Core/OsHle/Services/Am/IDebugFunctions.cs

@@ -3,11 +3,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Am
 {
-    class IDebugFunctions : IIpcService
+    class IDebugFunctions : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public IDebugFunctions()
         {

+ 2 - 2
Ryujinx.Core/OsHle/Services/Am/IDisplayController.cs

@@ -3,11 +3,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Am
 {
-    class IDisplayController : IIpcService
+    class IDisplayController : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public IDisplayController()
         {

+ 2 - 2
Ryujinx.Core/OsHle/Services/Am/ILibraryAppletCreator.cs

@@ -3,11 +3,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Am
 {
-    class ILibraryAppletCreator : IIpcService
+    class ILibraryAppletCreator : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ILibraryAppletCreator()
         {

+ 2 - 2
Ryujinx.Core/OsHle/Services/Am/ISelfController.cs

@@ -3,11 +3,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Am
 {
-    class ISelfController : IIpcService
+    class ISelfController : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ISelfController()
         {

+ 2 - 4
Ryujinx.Core/OsHle/Services/Am/IStorage.cs

@@ -1,15 +1,13 @@
 using Ryujinx.Core.OsHle.Ipc;
 using System.Collections.Generic;
 
-using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
-
 namespace Ryujinx.Core.OsHle.IpcServices.Am
 {
-    class IStorage : IIpcService
+    class IStorage : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public byte[] Data { get; private set; }
 

+ 2 - 2
Ryujinx.Core/OsHle/Services/Am/IStorageAccessor.cs

@@ -5,11 +5,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Am
 {
-    class IStorageAccessor : IIpcService
+    class IStorageAccessor : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         private IStorage Storage;
 

+ 2 - 2
Ryujinx.Core/OsHle/Services/Am/IWindowController.cs

@@ -3,11 +3,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Am
 {
-    class IWindowController : IIpcService
+    class IWindowController : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public IWindowController()
         {

+ 9 - 0
Ryujinx.Core/OsHle/Services/Am/MessageInfo.cs

@@ -0,0 +1,9 @@
+namespace Ryujinx.Core.OsHle.IpcServices.Am
+{
+    enum MessageInfo
+    {
+        FocusStateChanged      = 0xf,
+        OperationModeChanged   = 0x1e,
+        PerformanceModeChanged = 0x1f
+    }
+}

+ 8 - 0
Ryujinx.Core/OsHle/Services/Am/OperationMode.cs

@@ -0,0 +1,8 @@
+namespace Ryujinx.Core.OsHle.IpcServices.Am
+{
+    enum OperationMode
+    {
+        Handheld = 0,
+        Docked   = 1
+    }
+}

+ 2 - 4
Ryujinx.Core/OsHle/Services/Am/ServiceAppletOE.cs

@@ -1,15 +1,13 @@
 using Ryujinx.Core.OsHle.Ipc;
 using System.Collections.Generic;
 
-using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
-
 namespace Ryujinx.Core.OsHle.IpcServices.Am
 {
-    class ServiceAppletOE : IIpcService
+    class ServiceAppletOE : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ServiceAppletOE()
         {

+ 2 - 2
Ryujinx.Core/OsHle/Services/Apm/ISession.cs

@@ -3,11 +3,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Apm
 {
-    class ISession : IIpcService
+    class ISession : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ISession()
         {

+ 2 - 4
Ryujinx.Core/OsHle/Services/Apm/ServiceApm.cs

@@ -1,15 +1,13 @@
 using Ryujinx.Core.OsHle.Ipc;
 using System.Collections.Generic;
 
-using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
-
 namespace Ryujinx.Core.OsHle.IpcServices.Apm
 {
-    class ServiceApm : IIpcService
+    class ServiceApm : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ServiceApm()
         {

+ 2 - 2
Ryujinx.Core/OsHle/Services/Aud/IAudioDevice.cs

@@ -5,11 +5,11 @@ using System.Text;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Aud
 {
-    class IAudioDevice : IIpcService
+    class IAudioDevice : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public IAudioDevice()
         {

+ 11 - 6
Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs

@@ -7,17 +7,19 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Aud
 {
-    class IAudioOut : IIpcService, IDisposable
+    class IAudioOut : IpcService, IDisposable
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         private IAalOutput AudioOut;
 
+        private KEvent ReleaseEvent;
+
         private int Track;
 
-        public IAudioOut(IAalOutput AudioOut, int Track)
+        public IAudioOut(IAalOutput AudioOut, KEvent ReleaseEvent, int Track)
         {
             m_Commands = new Dictionary<int, ServiceProcessRequest>()
             {
@@ -32,8 +34,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
                 { 8, GetReleasedAudioOutBufferEx }
             };
 
-            this.AudioOut = AudioOut;
-            this.Track    = Track;
+            this.AudioOut     = AudioOut;
+            this.ReleaseEvent = ReleaseEvent;
+            this.Track        = Track;
         }
 
         public long GetAudioOutState(ServiceCtx Context)
@@ -77,7 +80,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
 
         public long RegisterBufferEvent(ServiceCtx Context)
         {
-            int Handle = Context.Process.HandleTable.OpenHandle(new HEvent());
+            int Handle = Context.Process.HandleTable.OpenHandle(ReleaseEvent);
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
@@ -143,6 +146,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
             if (Disposing)
             {
                 AudioOut.CloseTrack(Track);
+
+                ReleaseEvent.Dispose();
             }
         }
     }

+ 24 - 3
Ryujinx.Core/OsHle/Services/Aud/IAudioRenderer.cs

@@ -1,14 +1,17 @@
 using Ryujinx.Core.OsHle.Handles;
 using Ryujinx.Core.OsHle.Ipc;
+using System;
 using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Aud
 {
-    class IAudioRenderer : IIpcService
+    class IAudioRenderer : IpcService, IDisposable
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+
+        private KEvent UpdateEvent;
 
         public IAudioRenderer()
         {
@@ -19,6 +22,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
                 { 6, StopAudioRenderer          },
                 { 7, QuerySystemEvent           }
             };
+
+            UpdateEvent = new KEvent();
         }
 
         public long RequestUpdateAudioRenderer(ServiceCtx Context)
@@ -41,6 +46,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
                 Context.Memory.WriteInt32(Position + Offset, 5);
             }
 
+            //TODO: We shouldn't be signaling this here.
+            UpdateEvent.Handle.Set();
+
             return 0;
         }
 
@@ -56,11 +64,24 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
 
         public long QuerySystemEvent(ServiceCtx Context)
         {
-            int Handle = Context.Process.HandleTable.OpenHandle(new HEvent());
+            int Handle = Context.Process.HandleTable.OpenHandle(UpdateEvent);
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
             return 0;
         }
+
+        public void Dispose()
+        {
+            Dispose(true);
+        }
+
+        protected virtual void Dispose(bool Disposing)
+        {
+            if (Disposing)
+            {
+                UpdateEvent.Dispose();
+            }
+        }
     }
 }

+ 12 - 6
Ryujinx.Core/OsHle/Services/Aud/ServiceAudOut.cs

@@ -1,18 +1,17 @@
 using ChocolArm64.Memory;
 using Ryujinx.Audio;
+using Ryujinx.Core.OsHle.Handles;
 using Ryujinx.Core.OsHle.Ipc;
 using System.Collections.Generic;
 using System.Text;
 
-using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
-
 namespace Ryujinx.Core.OsHle.IpcServices.Aud
 {
-    class ServiceAudOut : IIpcService
+    class ServiceAudOut : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ServiceAudOut()
         {
@@ -73,9 +72,16 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
                 Channels = 2;
             }
 
-            int Track = AudioOut.OpenTrack(SampleRate, Channels, out AudioFormat Format);
+            KEvent ReleaseEvent = new KEvent();
+
+            ReleaseCallback Callback = () =>
+            {
+                ReleaseEvent.Handle.Set();
+            };
+
+            int Track = AudioOut.OpenTrack(SampleRate, Channels, Callback, out AudioFormat Format);
 
-            MakeObject(Context, new IAudioOut(AudioOut, Track));
+            MakeObject(Context, new IAudioOut(AudioOut, ReleaseEvent, Track));
 
             Context.ResponseData.Write(SampleRate);
             Context.ResponseData.Write(Channels);

+ 2 - 4
Ryujinx.Core/OsHle/Services/Aud/ServiceAudRen.cs

@@ -1,15 +1,13 @@
 using Ryujinx.Core.OsHle.Ipc;
 using System.Collections.Generic;
 
-using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
-
 namespace Ryujinx.Core.OsHle.IpcServices.Aud
 {
-    class ServiceAudRen : IIpcService
+    class ServiceAudRen : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ServiceAudRen()
         {

+ 2 - 2
Ryujinx.Core/OsHle/Services/Bsd/ServiceBsd.cs

@@ -51,11 +51,11 @@ namespace Ryujinx.Core.OsHle.IpcServices.Bsd
         public Socket Handle;
     }
 
-    class ServiceBsd : IIpcService
+    class ServiceBsd : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         private List<SocketBsd> Sockets = new List<SocketBsd>();
 

+ 2 - 2
Ryujinx.Core/OsHle/Services/Friend/IFriendService.cs

@@ -3,11 +3,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Friend
 {
-    class IFriendService : IIpcService
+    class IFriendService : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public IFriendService()
         {

+ 2 - 4
Ryujinx.Core/OsHle/Services/Friend/ServiceFriend.cs

@@ -1,15 +1,13 @@
 using Ryujinx.Core.OsHle.Ipc;
 using System.Collections.Generic;
 
-using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
-
 namespace Ryujinx.Core.OsHle.IpcServices.Friend
 {
-    class ServiceFriend : IIpcService
+    class ServiceFriend : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ServiceFriend()
         {

+ 2 - 2
Ryujinx.Core/OsHle/Services/FspSrv/IDirectory.cs

@@ -7,13 +7,13 @@ using System.Text;
 
 namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
 {
-    class IDirectory : IIpcService, IDisposable
+    class IDirectory : IpcService, IDisposable
     {
         private const int DirectoryEntrySize = 0x310;
 
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         private List<string> DirectoryEntries;
 

+ 2 - 2
Ryujinx.Core/OsHle/Services/FspSrv/IFile.cs

@@ -6,11 +6,11 @@ using System.IO;
 
 namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
 {
-    class IFile : IIpcService, IDisposable
+    class IFile : IpcService, IDisposable
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         private Stream BaseStream;
 

+ 2 - 3
Ryujinx.Core/OsHle/Services/FspSrv/IFileSystem.cs

@@ -5,15 +5,14 @@ using System.IO;
 using System.Text;
 
 using static Ryujinx.Core.OsHle.ErrorCode;
-using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
 
 namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
 {
-    class IFileSystem : IIpcService
+    class IFileSystem : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         private HashSet<string> OpenPaths;
 

+ 2 - 2
Ryujinx.Core/OsHle/Services/FspSrv/IStorage.cs

@@ -5,11 +5,11 @@ using System.IO;
 
 namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
 {
-    class IStorage : IIpcService
+    class IStorage : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         private Stream BaseStream;
 

+ 2 - 4
Ryujinx.Core/OsHle/Services/FspSrv/ServiceFspSrv.cs

@@ -1,15 +1,13 @@
 using Ryujinx.Core.OsHle.Ipc;
 using System.Collections.Generic;
 
-using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
-
 namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
 {
-    class ServiceFspSrv : IIpcService
+    class ServiceFspSrv : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ServiceFspSrv()
         {

+ 2 - 2
Ryujinx.Core/OsHle/Services/Hid/IActiveVibrationDeviceList.cs

@@ -3,11 +3,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Hid
 {
-    class IActiveApplicationDeviceList : IIpcService
+    class IActiveApplicationDeviceList : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public IActiveApplicationDeviceList()
         {

+ 2 - 2
Ryujinx.Core/OsHle/Services/Hid/IAppletResource.cs

@@ -4,11 +4,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Hid
 {
-    class IAppletResource : IIpcService
+    class IAppletResource : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         private HSharedMem HidSharedMem;
 

+ 2 - 4
Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs

@@ -2,15 +2,13 @@ using Ryujinx.Core.OsHle.Ipc;
 using System.Collections.Generic;
 using Ryujinx.Core.Input;
 
-using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
-
 namespace Ryujinx.Core.OsHle.IpcServices.Hid
 {
-    class ServiceHid : IIpcService
+    class ServiceHid : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ServiceHid()
         {

+ 151 - 0
Ryujinx.Core/OsHle/Services/IpcService.cs

@@ -0,0 +1,151 @@
+using Ryujinx.Core.OsHle.Ipc;
+using Ryujinx.Core.OsHle.Handles;
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace Ryujinx.Core.OsHle.IpcServices
+{
+    abstract class IpcService : IIpcService
+    {
+        public abstract IReadOnlyDictionary<int, ServiceProcessRequest> Commands { get; }
+
+        private IdDictionary DomainObjects;
+
+        private int SelfId;
+
+        private bool IsDomain;       
+
+        public IpcService()
+        {
+            DomainObjects = new IdDictionary();
+
+            SelfId = -1;
+        }
+
+        public int ConvertToDomain()
+        {
+            if (SelfId == -1)
+            {
+                SelfId = DomainObjects.Add(this);
+            }
+
+            IsDomain = true;
+
+            return SelfId;
+        }
+
+        public void ConvertToSession()
+        {
+            IsDomain = false;
+        }
+
+        public void CallMethod(ServiceCtx Context)
+        {
+            IIpcService Service = this;
+
+            if (IsDomain)
+            {
+                int DomainWord0 = Context.RequestData.ReadInt32();
+                int DomainObjId = Context.RequestData.ReadInt32();
+
+                long Padding = Context.RequestData.ReadInt64();
+
+                int DomainCmd = DomainWord0 & 0xff;
+
+                if (DomainCmd == 1)
+                {
+                    Service = GetObject(DomainObjId);
+
+                    Context.ResponseData.Write(0L);
+                    Context.ResponseData.Write(0L);
+                }
+                else if (DomainCmd == 2)
+                {
+                    Delete(DomainObjId);
+
+                    Context.ResponseData.Write(0L);
+
+                    return;
+                }
+                else
+                {
+                    throw new NotImplementedException($"Domain command: {DomainCmd}");
+                }
+            }
+
+            long SfciMagic =      Context.RequestData.ReadInt64();
+            int  CommandId = (int)Context.RequestData.ReadInt64();
+
+            if (Service.Commands.TryGetValue(CommandId, out ServiceProcessRequest ProcessRequest))
+            {
+                Context.ResponseData.BaseStream.Seek(IsDomain ? 0x20 : 0x10, SeekOrigin.Begin);
+
+                Logging.Trace($"{Service.GetType().Name}: {ProcessRequest.Method.Name}");
+
+                long Result = ProcessRequest(Context);
+
+                if (IsDomain)
+                {
+                    foreach (int Id in Context.Response.ResponseObjIds)
+                    {
+                        Context.ResponseData.Write(Id);
+                    }
+
+                    Context.ResponseData.BaseStream.Seek(0, SeekOrigin.Begin);
+
+                    Context.ResponseData.Write(Context.Response.ResponseObjIds.Count);
+                }
+
+                Context.ResponseData.BaseStream.Seek(IsDomain ? 0x10 : 0, SeekOrigin.Begin);
+
+                Context.ResponseData.Write(IpcMagic.Sfco);
+                Context.ResponseData.Write(Result);
+            }
+            else
+            {
+                throw new NotImplementedException($"{Service.GetType().Name}: {CommandId}");
+            }
+        }
+
+        protected static void MakeObject(ServiceCtx Context, IpcService Obj)
+        {
+            IpcService Service = Context.Session.Service;
+
+            if (Service.IsDomain)
+            {
+                Context.Response.ResponseObjIds.Add(Service.Add(Obj));
+            }
+            else
+            {
+                KSession Session = new KSession(Obj);
+
+                int Handle = Context.Process.HandleTable.OpenHandle(Session);
+
+                Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
+            }
+        }
+
+        private int Add(IIpcService Obj)
+        {
+            return DomainObjects.Add(Obj);
+        }
+
+        private bool Delete(int Id)
+        {
+            object Obj = DomainObjects.Delete(Id);
+
+            if (Obj is IDisposable DisposableObj)
+            {
+                DisposableObj.Dispose();
+            }
+
+            return Obj != null;
+        }
+
+        private IIpcService GetObject(int Id)
+        {
+            return DomainObjects.GetData<IIpcService>(Id);
+        }
+    }
+}

+ 2 - 2
Ryujinx.Core/OsHle/Services/Lm/ILogger.cs

@@ -7,11 +7,11 @@ using System.Text;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Lm
 {
-    class ILogger : IIpcService
+    class ILogger : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ILogger()
         {

+ 2 - 6
Ryujinx.Core/OsHle/Services/Lm/ServiceLm.cs

@@ -1,15 +1,13 @@
 using Ryujinx.Core.OsHle.Ipc;
 using System.Collections.Generic;
 
-using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
-
 namespace Ryujinx.Core.OsHle.IpcServices.Lm
 {
-    class ServiceLm : IIpcService
+    class ServiceLm : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ServiceLm()
         {
@@ -21,8 +19,6 @@ namespace Ryujinx.Core.OsHle.IpcServices.Lm
 
         public long Initialize(ServiceCtx Context)
         {
-            Context.Session.Initialize();
-
             MakeObject(Context, new ILogger());
 
             return 0;

+ 2 - 4
Ryujinx.Core/OsHle/Services/Nifm/IGeneralService.cs

@@ -1,15 +1,13 @@
 using Ryujinx.Core.OsHle.Ipc;
 using System.Collections.Generic;
 
-using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
-
 namespace Ryujinx.Core.OsHle.IpcServices.Nifm
 {
-    class IGeneralService : IIpcService
+    class IGeneralService : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public IGeneralService()
         {

+ 24 - 5
Ryujinx.Core/OsHle/Services/Nifm/IRequest.cs

@@ -1,13 +1,17 @@
+using Ryujinx.Core.OsHle.Handles;
 using Ryujinx.Core.OsHle.Ipc;
+using System;
 using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Nifm
 {
-    class IRequest : IIpcService
+    class IRequest : IpcService, IDisposable
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+
+        private KEvent Event;
 
         public IRequest()
         {
@@ -17,9 +21,10 @@ namespace Ryujinx.Core.OsHle.IpcServices.Nifm
                 { 1, GetResult                     },
                 { 2, GetSystemEventReadableHandles }
             };
+
+            Event = new KEvent();
         }
 
-        // -> i32
         public long GetRequestState(ServiceCtx Context)
         {
             Context.ResponseData.Write(0);
@@ -39,11 +44,25 @@ namespace Ryujinx.Core.OsHle.IpcServices.Nifm
         //GetSystemEventReadableHandles() -> (KObject, KObject)
         public long GetSystemEventReadableHandles(ServiceCtx Context)
         {
-            Context.Response.HandleDesc = IpcHandleDesc.MakeMove(0xbadcafe);
+            //FIXME: Is this supposed to return 2 events?
+            int Handle = Context.Process.HandleTable.OpenHandle(Event);
 
-            //Todo: Stub
+            Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
 
             return 0;
         }
+
+        public void Dispose()
+        {
+            Dispose(true);
+        }
+
+        protected virtual void Dispose(bool Disposing)
+        {
+            if (Disposing)
+            {
+                Event.Dispose();
+            }
+        }
     }
 }

+ 2 - 4
Ryujinx.Core/OsHle/Services/Nifm/ServiceNifm.cs

@@ -1,15 +1,13 @@
 using Ryujinx.Core.OsHle.Ipc;
 using System.Collections.Generic;
 
-using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
-
 namespace Ryujinx.Core.OsHle.IpcServices.Nifm
 {
-    class ServiceNifm : IIpcService
+    class ServiceNifm : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ServiceNifm()
         {

+ 2 - 2
Ryujinx.Core/OsHle/Services/Ns/ServiceNs.cs

@@ -3,11 +3,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Ns
 {
-    class ServiceNs : IIpcService
+    class ServiceNs : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ServiceNs()
         {

+ 41 - 22
Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs

@@ -1,4 +1,5 @@
 using ChocolArm64.Memory;
+using Ryujinx.Core.OsHle.Handles;
 using Ryujinx.Core.OsHle.Ipc;
 using Ryujinx.Core.OsHle.Utilities;
 using Ryujinx.Graphics.Gpu;
@@ -7,20 +8,22 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.NvServices
 {
-    class ServiceNvDrv : IIpcService
+    class ServiceNvDrv : IpcService, IDisposable
     {
         private delegate long ServiceProcessIoctl(ServiceCtx Context);
 
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         private Dictionary<(string, int), ServiceProcessIoctl> IoctlCmds;
 
-        private IdDictionary Fds;
+        public static GlobalStateTable Fds { get; private set; }
 
-        private IdDictionary NvMaps;
-        private IdDictionary NvMapsById;
+        public static GlobalStateTable NvMaps     { get; private set; }
+        public static GlobalStateTable NvMapsById { get; private set; }
+
+        private KEvent Event;
 
         public ServiceNvDrv()
         {
@@ -64,10 +67,15 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
                 { ("/dev/nvmap",           0x010e), NvMapIocGetId                     },
             };
 
-            Fds = new IdDictionary();
+            Event = new KEvent();
+        }
 
-            NvMaps     = new IdDictionary();
-            NvMapsById = new IdDictionary();
+        static ServiceNvDrv()
+        {
+            Fds = new GlobalStateTable();
+
+            NvMaps     = new GlobalStateTable();
+            NvMapsById = new GlobalStateTable();
         }
 
         public long Open(ServiceCtx Context)
@@ -76,7 +84,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
 
             string Name = AMemoryHelper.ReadAsciiString(Context.Memory, NamePtr);
 
-            int Fd = Fds.Add(new NvFd(Name));
+            int Fd = Fds.Add(Context.Process, new NvFd(Name));
 
             Context.ResponseData.Write(Fd);
             Context.ResponseData.Write(0);
@@ -89,7 +97,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             int Fd  = Context.RequestData.ReadInt32();
             int Cmd = Context.RequestData.ReadInt32() & 0xffff;
             
-            NvFd FdData = Fds.GetData<NvFd>(Fd);
+            NvFd FdData = Fds.GetData<NvFd>(Context.Process, Fd);
 
             long Position = Context.Request.GetSendBuffPtr();
 
@@ -109,7 +117,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
         {
             int Fd = Context.RequestData.ReadInt32();
 
-            Fds.Delete(Fd);
+            Fds.Delete(Context.Process, Fd);
 
             Context.ResponseData.Write(0);
 
@@ -131,7 +139,10 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             int Fd      = Context.RequestData.ReadInt32();
             int EventId = Context.RequestData.ReadInt32();
 
-            Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(0xcafe);
+            //TODO: Use Fd/EventId, different channels have different events.
+            int Handle = Context.Process.HandleTable.OpenHandle(Event);
+
+            Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
             Context.ResponseData.Write(0);
 
@@ -203,7 +214,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
                 return 0;
             }
 
-            NvMap Map = NvMaps.GetData<NvMap>(Handle);
+            NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
 
             if (Map == null)
             {
@@ -550,9 +561,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
 
             NvMap Map = new NvMap() { Size = Size };
 
-            Map.Handle = NvMaps.Add(Map);
+            Map.Handle = NvMaps.Add(Context.Process, Map);
 
-            Map.Id = NvMapsById.Add(Map);
+            Map.Id = NvMapsById.Add(Context.Process, Map);
 
             Context.Memory.WriteInt32(Position + 4, Map.Handle);
 
@@ -567,7 +578,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
 
             int Id = Context.Memory.ReadInt32(Position);
 
-            NvMap Map = NvMapsById.GetData<NvMap>(Id);
+            NvMap Map = NvMapsById.GetData<NvMap>(Context.Process, Id);
 
             if (Map == null)
             {
@@ -594,7 +605,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             byte Kind     = (byte)Reader.ReadInt64();
             long Addr     =       Reader.ReadInt64();
 
-            NvMap Map = NvMaps.GetData<NvMap>(Handle);
+            NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
 
             if (Map == null)
             {
@@ -620,7 +631,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             int  Handle  = Reader.ReadInt32();
             int  Padding = Reader.ReadInt32();
 
-            NvMap Map = NvMaps.GetData<NvMap>(Handle);
+            NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
 
             if (Map == null)
             {
@@ -645,7 +656,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             int Handle = Reader.ReadInt32();
             int Param  = Reader.ReadInt32();
 
-            NvMap Map = NvMaps.GetData<NvMap>(Handle);
+            NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
 
             if (Map == null)
             {
@@ -675,7 +686,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
 
             int Handle = Context.Memory.ReadInt32(Position + 4);
 
-            NvMap Map = NvMaps.GetData<NvMap>(Handle);
+            NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
 
             if (Map == null)
             {
@@ -689,9 +700,17 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        public NvMap GetNvMap(int Handle)
+        public void Dispose()
         {
-            return NvMaps.GetData<NvMap>(Handle);
+            Dispose(true);
+        }
+
+        protected virtual void Dispose(bool Disposing)
+        {
+            if (Disposing)
+            {
+                Event.Dispose();
+            }
         }
     }
 }

+ 0 - 24
Ryujinx.Core/OsHle/Services/ObjHelper.cs

@@ -1,24 +0,0 @@
-using Ryujinx.Core.OsHle.Handles;
-using Ryujinx.Core.OsHle.Ipc;
-
-namespace Ryujinx.Core.OsHle.IpcServices
-{
-    static class ObjHelper
-    {
-        public static void MakeObject(ServiceCtx Context, object Obj)
-        {
-            if (Context.Session is HDomain Dom)
-            {
-                Context.Response.ResponseObjIds.Add(Dom.Add(Obj));
-            }
-            else
-            {
-                HSessionObj HndData = new HSessionObj(Context.Session, Obj);
-
-                int VHandle = Context.Process.HandleTable.OpenHandle(HndData);
-
-                Context.Response.HandleDesc = IpcHandleDesc.MakeMove(VHandle);
-            }
-        }
-    }
-}

+ 2 - 2
Ryujinx.Core/OsHle/Services/Pctl/IParentalControlService.cs

@@ -3,11 +3,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Pctl
 {
-    class IParentalControlService : IIpcService
+    class IParentalControlService : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public IParentalControlService()
         {

+ 2 - 4
Ryujinx.Core/OsHle/Services/Pctl/ServicePctl.cs

@@ -1,15 +1,13 @@
 using Ryujinx.Core.OsHle.Ipc;
 using System.Collections.Generic;
 
-using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
-
 namespace Ryujinx.Core.OsHle.IpcServices.Pctl
 {
-    class ServicePctl : IIpcService
+    class ServicePctl : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ServicePctl()
         {

+ 2 - 2
Ryujinx.Core/OsHle/Services/Pl/ServicePl.cs

@@ -3,11 +3,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Pl
 {
-    class ServicePl : IIpcService
+    class ServicePl : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ServicePl()
         {

+ 119 - 0
Ryujinx.Core/OsHle/Services/ServiceFactory.cs

@@ -0,0 +1,119 @@
+using Ryujinx.Core.OsHle.IpcServices.Acc;
+using Ryujinx.Core.OsHle.IpcServices.Am;
+using Ryujinx.Core.OsHle.IpcServices.Apm;
+using Ryujinx.Core.OsHle.IpcServices.Aud;
+using Ryujinx.Core.OsHle.IpcServices.Bsd;
+using Ryujinx.Core.OsHle.IpcServices.Friend;
+using Ryujinx.Core.OsHle.IpcServices.FspSrv;
+using Ryujinx.Core.OsHle.IpcServices.Hid;
+using Ryujinx.Core.OsHle.IpcServices.Lm;
+using Ryujinx.Core.OsHle.IpcServices.Nifm;
+using Ryujinx.Core.OsHle.IpcServices.Ns;
+using Ryujinx.Core.OsHle.IpcServices.NvServices;
+using Ryujinx.Core.OsHle.IpcServices.Pctl;
+using Ryujinx.Core.OsHle.IpcServices.Pl;
+using Ryujinx.Core.OsHle.IpcServices.Set;
+using Ryujinx.Core.OsHle.IpcServices.Sfdnsres;
+using Ryujinx.Core.OsHle.IpcServices.Sm;
+using Ryujinx.Core.OsHle.IpcServices.Ssl;
+using Ryujinx.Core.OsHle.IpcServices.Time;
+using Ryujinx.Core.OsHle.IpcServices.Vi;
+using System;
+
+namespace Ryujinx.Core.OsHle.IpcServices
+{
+    static class ServiceFactory
+    {
+        public static IpcService MakeService(string Name)
+        {
+            switch (Name)
+            {
+                case "acc:u0":
+                    return new ServiceAcc();
+
+                case "aoc:u":
+                    return new ServiceNs();
+
+                case "apm":
+                    return new ServiceApm();
+
+                case "apm:p":
+                    return new ServiceApm();
+
+                case "appletOE":
+                    return new ServiceAppletOE();
+
+                case "audout:u":
+                    return new ServiceAudOut();
+
+                case "audren:u":
+                    return new ServiceAudRen();
+
+                case "bsd:s":
+                    return new ServiceBsd();
+
+                case "bsd:u":
+                    return new ServiceBsd();
+
+                case "friend:a":
+                    return new ServiceFriend();
+
+                case "fsp-srv":
+                    return new ServiceFspSrv();
+
+                case "hid":
+                    return new ServiceHid();
+
+                case "lm":
+                    return new ServiceLm();
+
+                case "nifm:u":
+                    return new ServiceNifm();
+
+                case "nvdrv":
+                    return new ServiceNvDrv();
+
+                case "nvdrv:a":
+                    return new ServiceNvDrv();
+
+                case "pctl:a":
+                    return new ServicePctl();
+
+                case "pl:u":
+                    return new ServicePl();
+
+                case "set":
+                    return new ServiceSet();
+
+                case "set:sys":
+                    return new ServiceSetSys();
+
+                case "sfdnsres":
+                    return new ServiceSfdnsres();
+
+                case "sm:":
+                    return new ServiceSm();
+
+                case "ssl":
+                    return new ServiceSsl();
+
+                case "time:s":
+                    return new ServiceTime();
+
+                case "time:u":
+                    return new ServiceTime();
+
+                case "vi:m":
+                    return new ServiceVi();
+
+                case "vi:s":
+                    return new ServiceVi();
+
+                case "vi:u":
+                    return new ServiceVi();
+            }
+
+            throw new NotImplementedException(Name);
+        }
+    }
+}

+ 2 - 2
Ryujinx.Core/OsHle/Services/Set/ServiceSet.cs

@@ -5,11 +5,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Set
 {
-    class ServiceSet : IIpcService
+    class ServiceSet : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ServiceSet()
         {

+ 2 - 2
Ryujinx.Core/OsHle/Services/Set/ServiceSetSys.cs

@@ -3,11 +3,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Set
 {
-    class ServiceSetSys : IIpcService
+    class ServiceSetSys : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ServiceSetSys()
         {

+ 2 - 2
Ryujinx.Core/OsHle/Services/Sfdnsres/ServiceSfdnsres.cs

@@ -3,11 +3,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Sfdnsres
 {
-    class ServiceSfdnsres : IIpcService
+    class ServiceSfdnsres : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ServiceSfdnsres()
         {

+ 7 - 5
Ryujinx.Core/OsHle/Services/Sm/ServiceSm.cs

@@ -4,11 +4,13 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Sm
 {
-    class ServiceSm : IIpcService
+    class ServiceSm : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+
+        private bool IsInitialized;
 
         public ServiceSm()
         {
@@ -23,7 +25,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Sm
 
         public long Initialize(ServiceCtx Context)
         {
-            Context.Session.Initialize();
+            IsInitialized = true;
 
             return 0;
         }
@@ -31,7 +33,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Sm
         public long GetService(ServiceCtx Context)
         {
             //Only for kernel version > 3.0.0.
-            if (!Context.Session.IsInitialized)
+            if (!IsInitialized)
             {
                 //return SmNotInitialized;
             }
@@ -55,7 +57,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Sm
                 return 0;
             }
 
-            HSession Session = new HSession(Context.Process.Services.GetService(Name));
+            KSession Session = new KSession(ServiceFactory.MakeService(Name));
 
             int Handle = Context.Process.HandleTable.OpenHandle(Session);
 

+ 2 - 2
Ryujinx.Core/OsHle/Services/Ssl/ServiceSsl.cs

@@ -3,11 +3,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Ssl
 {
-    class ServiceSsl : IIpcService
+    class ServiceSsl : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ServiceSsl()
         {

+ 2 - 2
Ryujinx.Core/OsHle/Services/Time/ISteadyClock.cs

@@ -3,11 +3,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Time
 {
-    class ISteadyClock : IIpcService
+    class ISteadyClock : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ISteadyClock()
         {

+ 2 - 2
Ryujinx.Core/OsHle/Services/Time/ISystemClock.cs

@@ -4,11 +4,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Time
 {
-    class ISystemClock : IIpcService
+    class ISystemClock : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         private static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
 

+ 2 - 2
Ryujinx.Core/OsHle/Services/Time/ITimeZoneService.cs

@@ -4,11 +4,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Time
 {
-    class ITimeZoneService : IIpcService
+    class ITimeZoneService : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         private static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local);
 

+ 2 - 4
Ryujinx.Core/OsHle/Services/Time/ServiceTime.cs

@@ -1,15 +1,13 @@
 using Ryujinx.Core.OsHle.Ipc;
 using System.Collections.Generic;
 
-using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
-
 namespace Ryujinx.Core.OsHle.IpcServices.Time
 {
-    class ServiceTime : IIpcService
+    class ServiceTime : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ServiceTime()
         {

+ 3 - 5
Ryujinx.Core/OsHle/Services/Vi/IApplicationDisplayService.cs

@@ -1,19 +1,17 @@
 using ChocolArm64.Memory;
-using Ryujinx.Core.OsHle.Handles;
 using Ryujinx.Core.OsHle.Ipc;
 using System.Collections.Generic;
 using System.IO;
 
 using static Ryujinx.Core.OsHle.IpcServices.Android.Parcel;
-using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Vi
 {
-    class IApplicationDisplayService : IIpcService
+    class IApplicationDisplayService : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         private IdDictionary Displays;
 
@@ -145,7 +143,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
         {
             string Name = GetDisplayName(Context);
 
-            int Handle = Context.Process.HandleTable.OpenHandle(new HEvent());
+            int Handle = Context.Process.HandleTable.OpenHandle(Context.Ns.Os.VsyncEvent);
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 

+ 13 - 4
Ryujinx.Core/OsHle/Services/Vi/IHOSBinderDriver.cs

@@ -1,4 +1,5 @@
 using ChocolArm64.Memory;
+using Ryujinx.Core.OsHle.Handles;
 using Ryujinx.Core.OsHle.Ipc;
 using Ryujinx.Core.OsHle.IpcServices.Android;
 using Ryujinx.Graphics.Gal;
@@ -7,11 +8,13 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Vi
 {
-    class IHOSBinderDriver : IIpcService, IDisposable
+    class IHOSBinderDriver : IpcService, IDisposable
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+
+        private KEvent ReleaseEvent;
 
         private NvFlinger Flinger;
 
@@ -24,7 +27,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
                 { 2, GetNativeHandle }
             };
 
-            Flinger = new NvFlinger(Renderer);
+            ReleaseEvent = new KEvent();
+
+            Flinger = new NvFlinger(Renderer, ReleaseEvent);
         }
 
         public long TransactParcel(ServiceCtx Context)
@@ -56,7 +61,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
             int  Id  = Context.RequestData.ReadInt32();
             uint Unk = Context.RequestData.ReadUInt32();
 
-            Context.Response.HandleDesc = IpcHandleDesc.MakeMove(0xbadcafe);
+            int Handle = Context.Process.HandleTable.OpenHandle(ReleaseEvent);
+
+            Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
 
             return 0;
         }
@@ -70,6 +77,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
         {
             if (Disposing)
             {
+                ReleaseEvent.Dispose();
+
                 Flinger.Dispose();
             }
         }

+ 2 - 2
Ryujinx.Core/OsHle/Services/Vi/IManagerDisplayService.cs

@@ -3,11 +3,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Vi
 {
-    class IManagerDisplayService : IIpcService
+    class IManagerDisplayService : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public IManagerDisplayService()
         {

+ 2 - 2
Ryujinx.Core/OsHle/Services/Vi/ISystemDisplayService.cs

@@ -3,11 +3,11 @@ using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.IpcServices.Vi
 {
-    class ISystemDisplayService : IIpcService
+    class ISystemDisplayService : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ISystemDisplayService()
         {

+ 14 - 8
Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs

@@ -1,4 +1,5 @@
 using ChocolArm64.Memory;
+using Ryujinx.Core.OsHle.Handles;
 using Ryujinx.Core.OsHle.IpcServices.NvServices;
 using Ryujinx.Graphics.Gal;
 using System;
@@ -17,6 +18,10 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
 
         private Dictionary<(string, int), ServiceProcessParcel> Commands;
 
+        private KEvent ReleaseEvent;
+
+        private IGalRenderer Renderer;
+
         private const int BufferQueueCount = 0x40;
         private const int BufferQueueMask  = BufferQueueCount - 1;
 
@@ -55,8 +60,6 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
             public GbpBuffer Data;
         }
 
-        private IGalRenderer Renderer;
-
         private BufferEntry[] BufferQueue;
 
         private ManualResetEvent WaitBufferFree;
@@ -69,7 +72,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
 
         private bool KeepRunning;
 
-        public NvFlinger(IGalRenderer Renderer)
+        public NvFlinger(IGalRenderer Renderer, KEvent ReleaseEvent)
         {
             Commands = new Dictionary<(string, int), ServiceProcessParcel>()
             {
@@ -83,8 +86,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
                 { ("android.gui.IGraphicBufferProducer", 0xb), GbpDisconnect     },
                 { ("android.gui.IGraphicBufferProducer", 0xe), GbpPreallocBuffer }
             };
-
-            this.Renderer = Renderer;
+            
+            this.Renderer     = Renderer;
+            this.ReleaseEvent = ReleaseEvent;
 
             BufferQueue = new BufferEntry[0x40];
 
@@ -293,6 +297,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
 
                 BufferQueue[Slot].State = BufferState.Free;
 
+                ReleaseEvent.Handle.Set();
+
                 WaitBufferFree.Set();
 
                 return;
@@ -377,6 +383,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
 
                 Interlocked.Decrement(ref RenderQueueCount);
 
+                ReleaseEvent.Handle.Set();
+
                 lock (WaitBufferFree)
                 {
                     WaitBufferFree.Set();
@@ -397,9 +405,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
                 NvMapHandle = BitConverter.ToInt32(RawValue, 0);
             }
 
-            ServiceNvDrv NvDrv = (ServiceNvDrv)Context.Process.Services.GetService("nvdrv");
-
-            return NvDrv.GetNvMap(NvMapHandle);
+            return ServiceNvDrv.NvMaps.GetData<NvMap>(Context.Process, NvMapHandle);
         }
 
         private int GetFreeSlotBlocking(int Width, int Height)

+ 2 - 4
Ryujinx.Core/OsHle/Services/Vi/ServiceVi.cs

@@ -1,15 +1,13 @@
 using Ryujinx.Core.OsHle.Ipc;
 using System.Collections.Generic;
 
-using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
-
 namespace Ryujinx.Core.OsHle.IpcServices.Vi
 {
-    class ServiceVi : IIpcService
+    class ServiceVi : IpcService
     {
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
-        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
         public ServiceVi()
         {

+ 103 - 48
Ryujinx.Core/OsHle/Svc/SvcSystem.cs

@@ -3,6 +3,7 @@ using ChocolArm64.State;
 using Ryujinx.Core.OsHle.Exceptions;
 using Ryujinx.Core.OsHle.Handles;
 using Ryujinx.Core.OsHle.Ipc;
+using Ryujinx.Core.OsHle.IpcServices;
 using System;
 using System.Threading;
 
@@ -34,7 +35,28 @@ namespace Ryujinx.Core.OsHle.Svc
         {
             int Handle = (int)ThreadState.X0;
 
-            Process.HandleTable.CloseHandle(Handle);
+            object Obj = Process.HandleTable.CloseHandle(Handle);
+
+            if (Obj == null)
+            {
+                Logging.Warn($"Tried to CloseHandle on invalid handle 0x{Handle:x8}!");
+
+                ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
+
+                return;
+            }
+
+            if (Obj is KSession Session)
+            {
+                Session.Dispose();
+            }
+            else if (Obj is HTransferMem TMem)
+            {
+                TMem.Memory.Manager.Reprotect(
+                    TMem.Position,
+                    TMem.Size,
+                    TMem.Perm);
+            }
 
             ThreadState.X0 = 0;
         }
@@ -43,25 +65,78 @@ namespace Ryujinx.Core.OsHle.Svc
         {
             int Handle = (int)ThreadState.X0;
 
-            //TODO: Implement events.
+            KEvent Event = Process.HandleTable.GetData<KEvent>(Handle);
 
-            ThreadState.X0 = 0;
+            if (Event != null)
+            {
+                Event.Handle.Reset();
+
+                ThreadState.X0 = 0;
+            }
+            else
+            {
+                Logging.Warn($"Tried to ResetSignal on invalid event handle 0x{Handle:x8}!");
+
+                ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
+            }
         }
 
         private void SvcWaitSynchronization(AThreadState ThreadState)
         {
-            long HandlesPtr   = (long)ThreadState.X0;
+            long HandlesPtr   = (long)ThreadState.X1;
             int  HandlesCount =  (int)ThreadState.X2;
             long Timeout      = (long)ThreadState.X3;
 
-            //TODO: Implement events.
+            KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
 
-            HThread CurrThread = Process.GetThread(ThreadState.Tpidr);
+            WaitHandle[] Handles = new WaitHandle[HandlesCount];
+
+            for (int Index = 0; Index < HandlesCount; Index++)
+            {
+                int Handle = Memory.ReadInt32(HandlesPtr + Index * 4);
+
+                KSynchronizationObject SyncObj = Process.HandleTable.GetData<KSynchronizationObject>(Handle);
+
+                if (SyncObj == null)
+                {
+                    Logging.Warn($"Tried to WaitSynchronization on invalid handle 0x{Handle:x8}!");
+
+                    ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
+
+                    return;
+                }
+
+                Handles[Index] = SyncObj.Handle;
+            }
 
             Process.Scheduler.Suspend(CurrThread.ProcessorId);
+
+            int HandleIndex;
+
+            ulong Result = 0;
+
+            if (Timeout != -1)
+            {
+                HandleIndex = WaitHandle.WaitAny(Handles, (int)(Timeout / 1000000));
+
+                if (HandleIndex == WaitHandle.WaitTimeout)
+                {
+                    Result = MakeError(ErrorModule.Kernel, KernelErr.Timeout);
+                }
+            }
+            else
+            {
+                HandleIndex = WaitHandle.WaitAny(Handles);
+            }
+
             Process.Scheduler.Resume(CurrThread);
 
-            ThreadState.X0 = 0;
+            ThreadState.X0 = Result;
+
+            if (Result == 0)
+            {
+                ThreadState.X1 = (ulong)HandleIndex;
+            }
         }
 
         private void SvcGetSystemTick(AThreadState ThreadState)
@@ -78,8 +153,7 @@ namespace Ryujinx.Core.OsHle.Svc
 
             //TODO: Validate that app has perms to access the service, and that the service
             //actually exists, return error codes otherwise.
-
-            HSession Session = new HSession(Process.Services.GetService(Name));
+            KSession Session = new KSession(ServiceFactory.MakeService(Name));
 
             ulong Handle = (ulong)Process.HandleTable.OpenHandle(Session);
             
@@ -89,65 +163,46 @@ namespace Ryujinx.Core.OsHle.Svc
 
         private void SvcSendSyncRequest(AThreadState ThreadState)
         {
-            SendSyncRequest(ThreadState, false);
+            SendSyncRequest(ThreadState, ThreadState.Tpidr, 0x100, (int)ThreadState.X0);
         }
 
         private void SvcSendSyncRequestWithUserBuffer(AThreadState ThreadState)
         {
-            SendSyncRequest(ThreadState, true);
+            SendSyncRequest(
+                      ThreadState,
+                (long)ThreadState.X0,
+                (long)ThreadState.X1,
+                 (int)ThreadState.X2);
         }
 
-        private void SendSyncRequest(AThreadState ThreadState, bool UserBuffer)
+        private void SendSyncRequest(AThreadState ThreadState, long CmdPtr, long Size, int Handle)
         {
-            long CmdPtr = ThreadState.Tpidr;
-            long Size   = 0x100;
-            int  Handle = 0;
+            KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
 
-            if (UserBuffer)
-            {
-                CmdPtr = (long)ThreadState.X0;
-                Size   = (long)ThreadState.X1;
-                Handle =  (int)ThreadState.X2;
-            }
-            else
-            {
-                Handle = (int)ThreadState.X0;
-            }
+            byte[] CmdData = AMemoryHelper.ReadBytes(Memory, CmdPtr, Size);
 
-            HThread CurrThread = Process.GetThread(ThreadState.Tpidr);
+            KSession Session = Process.HandleTable.GetData<KSession>(Handle);
 
-            Process.Scheduler.Suspend(CurrThread.ProcessorId);
+            if (Session != null)
+            {
+                Process.Scheduler.Suspend(CurrThread.ProcessorId);
 
-            byte[] CmdData = AMemoryHelper.ReadBytes(Memory, CmdPtr, Size);
+                IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr);
 
-            HSession Session = Process.HandleTable.GetData<HSession>(Handle);
+                IpcHandler.IpcCall(Ns, Process, Memory, Session, Cmd, CmdPtr);
 
-            IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr, Session is HDomain);
+                Thread.Yield();
 
-            if (Session != null)
-            {
-                IpcHandler.IpcCall(
-                    Ns,
-                    Process,
-                    Memory,
-                    Session,
-                    Cmd,
-                    ThreadState.ThreadId,
-                    CmdPtr,
-                    Handle);
-
-                byte[] Response = AMemoryHelper.ReadBytes(Memory, CmdPtr, Size);
+                Process.Scheduler.Resume(CurrThread);
 
                 ThreadState.X0 = 0;
             }
             else
             {
-                ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidIpcReq);
-            }
+                Logging.Warn($"Tried to SendSyncRequest on invalid session handle 0x{Handle:x8}!");
 
-            Thread.Yield();
-
-            Process.Scheduler.Resume(CurrThread);
+                ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
+            }
         }
 
         private void SvcBreak(AThreadState ThreadState)

+ 10 - 8
Ryujinx.Core/OsHle/Svc/SvcThread.cs

@@ -39,7 +39,7 @@ namespace Ryujinx.Core.OsHle.Svc
         {
             int Handle = (int)ThreadState.X0;
 
-            HThread Thread = Process.HandleTable.GetData<HThread>(Handle);
+            KThread Thread = Process.HandleTable.GetData<KThread>(Handle);
 
             if (Thread != null)
             {
@@ -53,16 +53,18 @@ namespace Ryujinx.Core.OsHle.Svc
 
         private void SvcExitThread(AThreadState ThreadState)
         {
-            HThread CurrThread = Process.GetThread(ThreadState.Tpidr);
-            
+            KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
+
             CurrThread.Thread.StopExecution();
+
+            CurrThread.Handle.Set();
         }
 
         private void SvcSleepThread(AThreadState ThreadState)
         {           
             ulong NanoSecs = ThreadState.X0;
 
-            HThread CurrThread = Process.GetThread(ThreadState.Tpidr);
+            KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
             
             if (NanoSecs == 0)
             {
@@ -78,7 +80,7 @@ namespace Ryujinx.Core.OsHle.Svc
         {
             int Handle = (int)ThreadState.X1;
 
-            HThread Thread = Process.HandleTable.GetData<HThread>(Handle);
+            KThread Thread = Process.HandleTable.GetData<KThread>(Handle);
 
             if (Thread != null)
             {
@@ -91,10 +93,10 @@ namespace Ryujinx.Core.OsHle.Svc
 
         private void SvcSetThreadPriority(AThreadState ThreadState)
         {
+            int Prio   = (int)ThreadState.X0;
             int Handle = (int)ThreadState.X1;
-            int Prio = (int)ThreadState.X0;
 
-            HThread Thread = Process.HandleTable.GetData<HThread>(Handle);
+            KThread Thread = Process.HandleTable.GetData<KThread>(Handle);
 
             if (Thread != null)
             {
@@ -117,7 +119,7 @@ namespace Ryujinx.Core.OsHle.Svc
         {
             int Handle = (int)ThreadState.X0;
 
-            HThread Thread = Process.HandleTable.GetData<HThread>(Handle);
+            KThread Thread = Process.HandleTable.GetData<KThread>(Handle);
 
             if (Thread != null)
             {

+ 3 - 3
Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs

@@ -13,7 +13,7 @@ namespace Ryujinx.Core.OsHle.Svc
             long MutexAddress           = (long)ThreadState.X1;
             int  RequestingThreadHandle =  (int)ThreadState.X2;
 
-            HThread RequestingThread = Process.HandleTable.GetData<HThread>(RequestingThreadHandle);
+            KThread RequestingThread = Process.HandleTable.GetData<KThread>(RequestingThreadHandle);
 
             Mutex M = new Mutex(Process, MutexAddress, OwnerThreadHandle);
 
@@ -43,7 +43,7 @@ namespace Ryujinx.Core.OsHle.Svc
             int  ThreadHandle   =  (int)ThreadState.X2;
             long Timeout        = (long)ThreadState.X3;
 
-            HThread Thread = Process.HandleTable.GetData<HThread>(ThreadHandle);
+            KThread Thread = Process.HandleTable.GetData<KThread>(ThreadHandle);
 
             Mutex M = new Mutex(Process, MutexAddress, ThreadHandle);
 
@@ -72,7 +72,7 @@ namespace Ryujinx.Core.OsHle.Svc
             long CondVarAddress = (long)ThreadState.X0;
             int  Count          =  (int)ThreadState.X1;
 
-            HThread CurrThread = Process.GetThread(ThreadState.Tpidr);
+            KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
 
             if (Ns.Os.CondVars.TryGetValue(CondVarAddress, out CondVar Cv))
             {

+ 5 - 5
Ryujinx.Core/Switch.cs

@@ -14,10 +14,10 @@ namespace Ryujinx.Core
 
         internal NsGpu Gpu { get; private set; }
 
-        internal Horizon Os { get; private set; }
-
         internal VirtualFileSystem VFs { get; private set; }
 
+        public Horizon Os { get; private set; }
+
         public SystemSettings Settings { get; private set; }
 
         public PerformanceStatistics Statistics { get; private set; }
@@ -40,12 +40,12 @@ namespace Ryujinx.Core
 
             this.AudioOut = AudioOut;
 
-            Gpu = new NsGpu(Renderer);
-
-            Os = new Horizon(this);
+            Gpu = new NsGpu(Renderer);            
 
             VFs = new VirtualFileSystem();
 
+            Os = new Horizon(this);
+
             Settings = new SystemSettings();
 
             Statistics = new PerformanceStatistics();

+ 44 - 15
Ryujinx.Graphics/Gpu/NsGpuPGraph.cs

@@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.Gpu
     {
         private NsGpu Gpu;
 
-        private int[] Registers;
+        private uint[] Registers;
 
         public NsGpuEngine[] SubChannels;
 
@@ -18,7 +18,7 @@ namespace Ryujinx.Graphics.Gpu
         {
             this.Gpu = Gpu;
 
-            Registers = new int[0x1000];
+            Registers = new uint[0x1000];
 
             SubChannels = new NsGpuEngine[8];
 
@@ -33,7 +33,7 @@ namespace Ryujinx.Graphics.Gpu
             {
                 if (Entry.Arguments.Count == 1)
                 {
-                    SetRegister(Entry.Register, Entry.Arguments[0]);
+                    SetRegister(Entry.Register, (uint)Entry.Arguments[0]);
                 }
 
                 switch (Entry.Register)
@@ -48,7 +48,7 @@ namespace Ryujinx.Graphics.Gpu
                     case NsGpuRegister._3dVertexArray0Fetch:
                         SendVertexBuffers(Memory);
                         break;
-                    
+
                     case NsGpuRegister._3dCbData0:
                         if (GetRegister(NsGpuRegister._3dCbPos) == 0x20)
                         {
@@ -62,6 +62,22 @@ namespace Ryujinx.Graphics.Gpu
                     case NsGpuRegister._3dQueryGet:
                         HasQuery = true;
                         break;
+
+                    case NsGpuRegister._3dSetShader:
+                        uint ShaderPrg  = (uint)Entry.Arguments[0];
+                        uint ShaderId   = (uint)Entry.Arguments[1];
+                        uint CodeAddr   = (uint)Entry.Arguments[2];
+                        uint ShaderType = (uint)Entry.Arguments[3];
+                        uint CodeEnd    = (uint)Entry.Arguments[4];
+
+                        SendShader(
+                            Memory,
+                            ShaderPrg,
+                            ShaderId,
+                            CodeAddr,
+                            ShaderType,
+                            CodeEnd);
+                        break;
                 }
             }
 
@@ -71,10 +87,10 @@ namespace Ryujinx.Graphics.Gpu
                     (long)GetRegister(NsGpuRegister._3dQueryAddressHigh) << 32 |
                     (long)GetRegister(NsGpuRegister._3dQueryAddressLow)  << 0;
 
-                int Seq = GetRegister(NsGpuRegister._3dQuerySequence);
-                int Get = GetRegister(NsGpuRegister._3dQueryGet);
+                uint Seq = GetRegister(NsGpuRegister._3dQuerySequence);
+                uint Get = GetRegister(NsGpuRegister._3dQueryGet);
 
-                int Mode = Get & 3;
+                uint Mode = Get & 3;
 
                 if (Mode == 0)
                 {
@@ -85,7 +101,7 @@ namespace Ryujinx.Graphics.Gpu
                     {
                         Gpu.Renderer.QueueAction(delegate()
                         {
-                            Memory.WriteInt32(Position, Seq);
+                            Memory.WriteUInt32(Position, Seq);
                         });
                     }
                 }
@@ -119,13 +135,13 @@ namespace Ryujinx.Graphics.Gpu
                 {
                     byte[] Buffer = AMemoryHelper.ReadBytes(Memory, Position, Size);
 
-                    int Stride = GetRegister(NsGpuRegister._3dVertexArray0Fetch) & 0xfff;
+                    int Stride = (int)GetRegister(NsGpuRegister._3dVertexArray0Fetch) & 0xfff;
 
                     List<GalVertexAttrib> Attribs = new List<GalVertexAttrib>();
 
                     for (int Attr = 0; Attr < 16; Attr++)
                     {
-                        int Packed = GetRegister(NsGpuRegister._3dVertexAttrib0Format + Attr * 4);
+                        int Packed = (int)GetRegister(NsGpuRegister._3dVertexAttrib0Format + Attr * 4);
 
                         GalVertexAttrib Attrib = new GalVertexAttrib(Attr,
                                                   (Packed >>  0) & 0x1f,
@@ -154,10 +170,10 @@ namespace Ryujinx.Graphics.Gpu
             long TicPos = (long)GetRegister(NsGpuRegister._3dTicAddressHigh) << 32 |
                           (long)GetRegister(NsGpuRegister._3dTicAddressLow)  << 0;
 
-            int CbData = GetRegister(NsGpuRegister._3dCbData0);
+            uint CbData = GetRegister(NsGpuRegister._3dCbData0);
 
-            int TicIndex = (CbData >>  0) & 0xfffff;
-            int TscIndex = (CbData >> 20) & 0xfff; //I guess?
+            uint TicIndex = (CbData >>  0) & 0xfffff;
+            uint TscIndex = (CbData >> 20) & 0xfff; //I guess?
 
             TicPos = Gpu.MemoryMgr.GetCpuAddr(TicPos + TicIndex * 0x20);
 
@@ -198,6 +214,19 @@ namespace Ryujinx.Graphics.Gpu
             }
         }
 
+        private void SendShader(
+            AMemory Memory,
+            uint    ShaderPrg,
+            uint    ShaderId,
+            uint    CodeAddr,
+            uint    ShaderType,
+            uint    CodeEnd)
+        {
+            long CodePos = Gpu.MemoryMgr.GetCpuAddr(CodeAddr);
+
+            byte[] Data = AMemoryHelper.ReadBytes(Memory, CodePos, 0x300);
+        }
+
         private static byte[] GetDecodedTexture(
             AMemory            Memory,
             NsGpuTextureFormat Format,
@@ -263,12 +292,12 @@ namespace Ryujinx.Graphics.Gpu
             return Data;
         }
 
-        public int GetRegister(NsGpuRegister Register)
+        public uint GetRegister(NsGpuRegister Register)
         {
             return Registers[((int)Register >> 2) & 0xfff];
         }
 
-        public void SetRegister(NsGpuRegister Register, int Value)
+        public void SetRegister(NsGpuRegister Register, uint Value)
         {
             Registers[((int)Register >> 2) & 0xfff] = Value;
         }

+ 1 - 0
Ryujinx.Graphics/Gpu/NsGpuRegister.cs

@@ -89,5 +89,6 @@ namespace Ryujinx.Graphics.Gpu
         _3dCbData13               = 0x23c4,
         _3dCbData14               = 0x23c8,
         _3dCbData15               = 0x23cc,
+        _3dSetShader              = 0x3890
     }
 }

Некоторые файлы не были показаны из-за большого количества измененных файлов