From 7de7b559adc1924d3ff31cc58b281f70e468155f Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sun, 23 Sep 2018 15:11:46 -0300 Subject: [PATCH] Improve kernel events implementation (#430) * Improve kernel events implementation * Some cleanup * Address PR feedback --- Ryujinx.HLE/HOS/Horizon.cs | 6 +- Ryujinx.HLE/HOS/Ipc/IpcHandler.cs | 5 +- Ryujinx.HLE/HOS/Kernel/HleScheduler.cs | 9 + Ryujinx.HLE/HOS/Kernel/KAddressArbiter.cs | 4 +- Ryujinx.HLE/HOS/Kernel/KEvent.cs | 36 +--- Ryujinx.HLE/HOS/Kernel/KHandleEntry.cs | 17 ++ Ryujinx.HLE/HOS/Kernel/KProcessHandleTable.cs | 173 ++++++++++++++++-- Ryujinx.HLE/HOS/Kernel/KReadableEvent.cs | 62 +++++++ Ryujinx.HLE/HOS/Kernel/KScheduler.cs | 7 - Ryujinx.HLE/HOS/Kernel/KWritableEvent.cs | 22 +++ Ryujinx.HLE/HOS/Kernel/KernelErr.cs | 1 + Ryujinx.HLE/HOS/Kernel/KernelResult.cs | 10 + Ryujinx.HLE/HOS/Kernel/SvcHandler.cs | 23 +-- Ryujinx.HLE/HOS/Kernel/SvcMemory.cs | 8 +- Ryujinx.HLE/HOS/Kernel/SvcSystem.cs | 140 ++++++++++++-- Ryujinx.HLE/HOS/Kernel/SvcThread.cs | 22 +-- Ryujinx.HLE/HOS/Kernel/SvcThreadSync.cs | 16 +- Ryujinx.HLE/HOS/Process.cs | 29 ++- .../HOS/Services/Am/ICommonStateGetter.cs | 11 +- .../HOS/Services/Am/IHomeMenuFunctions.cs | 6 +- .../HOS/Services/Am/ILibraryAppletAccessor.cs | 8 +- .../HOS/Services/Am/ISelfController.cs | 8 +- .../HOS/Services/Aud/AudioOut/IAudioOut.cs | 5 +- .../Aud/AudioRenderer/IAudioRenderer.cs | 7 +- Ryujinx.HLE/HOS/Services/Aud/IAudioDevice.cs | 18 +- .../HOS/Services/Aud/IAudioOutManager.cs | 2 +- .../HOS/Services/Hid/IAppletResource.cs | 6 +- Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs | 24 ++- Ryujinx.HLE/HOS/Services/IpcService.cs | 7 +- Ryujinx.HLE/HOS/Services/Nfp/IUser.cs | 16 +- Ryujinx.HLE/HOS/Services/Nifm/IRequest.cs | 12 +- Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs | 5 +- .../HOS/Services/Pl/ISharedFontManager.cs | 7 +- Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs | 6 +- .../Services/Vi/IApplicationDisplayService.cs | 7 +- .../HOS/Services/Vi/IHOSBinderDriver.cs | 7 +- Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs | 2 +- Ryujinx.HLE/HOS/SystemState/AppletStateMgr.cs | 4 +- 38 files changed, 597 insertions(+), 161 deletions(-) create mode 100644 Ryujinx.HLE/HOS/Kernel/KHandleEntry.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/KReadableEvent.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/KWritableEvent.cs create mode 100644 Ryujinx.HLE/HOS/Kernel/KernelResult.cs diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs index f8ec89140..d52c8af0a 100644 --- a/Ryujinx.HLE/HOS/Horizon.cs +++ b/Ryujinx.HLE/HOS/Horizon.cs @@ -71,6 +71,8 @@ namespace Ryujinx.HLE.HOS Withholders = new LinkedList(); + Scheduler.StartAutoPreemptionThread(); + if (!Device.Memory.Allocator.TryAllocate(HidSize, out long HidPA) || !Device.Memory.Allocator.TryAllocate(FontSize, out long FontPA)) { @@ -212,7 +214,7 @@ namespace Ryujinx.HLE.HOS } MainNca.SetBaseNca(PatchNca); - + if (ControlNca != null) { ReadControlData(ControlNca); @@ -466,7 +468,7 @@ namespace Ryujinx.HLE.HOS public void SignalVsync() { - VsyncEvent.Signal(); + VsyncEvent.ReadableEvent.Signal(); } private Process MakeProcess(Npdm MetaData = null) diff --git a/Ryujinx.HLE/HOS/Ipc/IpcHandler.cs b/Ryujinx.HLE/HOS/Ipc/IpcHandler.cs index 08a4cdb5d..fca995c08 100644 --- a/Ryujinx.HLE/HOS/Ipc/IpcHandler.cs +++ b/Ryujinx.HLE/HOS/Ipc/IpcHandler.cs @@ -73,7 +73,10 @@ namespace Ryujinx.HLE.HOS.Ipc { int Unknown = ReqReader.ReadInt32(); - int Handle = Process.HandleTable.OpenHandle(Session); + if (Process.HandleTable.GenerateHandle(Session, out int Handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); diff --git a/Ryujinx.HLE/HOS/Kernel/HleScheduler.cs b/Ryujinx.HLE/HOS/Kernel/HleScheduler.cs index 42caeca2d..e0cb158c9 100644 --- a/Ryujinx.HLE/HOS/Kernel/HleScheduler.cs +++ b/Ryujinx.HLE/HOS/Kernel/HleScheduler.cs @@ -15,6 +15,15 @@ namespace Ryujinx.HLE.HOS.Kernel private bool KeepPreempting; + public void StartAutoPreemptionThread() + { + Thread PreemptionThread = new Thread(PreemptCurrentThread); + + KeepPreempting = true; + + PreemptionThread.Start(); + } + public void ContextSwitch() { lock (CoreContexts) diff --git a/Ryujinx.HLE/HOS/Kernel/KAddressArbiter.cs b/Ryujinx.HLE/HOS/Kernel/KAddressArbiter.cs index f2156a5c2..73309e1e2 100644 --- a/Ryujinx.HLE/HOS/Kernel/KAddressArbiter.cs +++ b/Ryujinx.HLE/HOS/Kernel/KAddressArbiter.cs @@ -51,7 +51,7 @@ namespace Ryujinx.HLE.HOS.Kernel return 0; } - KThread MutexOwner = Process.HandleTable.GetData(OwnerHandle); + KThread MutexOwner = Process.HandleTable.GetObject(OwnerHandle); if (MutexOwner == null) { @@ -282,7 +282,7 @@ namespace Ryujinx.HLE.HOS.Kernel MutexValue &= ~HasListenersMask; - KThread MutexOwner = Process.HandleTable.GetData(MutexValue); + KThread MutexOwner = Process.HandleTable.GetObject(MutexValue); if (MutexOwner != null) { diff --git a/Ryujinx.HLE/HOS/Kernel/KEvent.cs b/Ryujinx.HLE/HOS/Kernel/KEvent.cs index 1a865aa20..106d1b409 100644 --- a/Ryujinx.HLE/HOS/Kernel/KEvent.cs +++ b/Ryujinx.HLE/HOS/Kernel/KEvent.cs @@ -1,38 +1,14 @@ namespace Ryujinx.HLE.HOS.Kernel { - class KEvent : KSynchronizationObject + class KEvent { - private bool Signaled; + public KReadableEvent ReadableEvent { get; private set; } + public KWritableEvent WritableEvent { get; private set; } - public string Name { get; private set; } - - public KEvent(Horizon System, string Name = "") : base(System) + public KEvent(Horizon System) { - this.Name = Name; - } - - public override void Signal() - { - System.CriticalSectionLock.Lock(); - - if (!Signaled) - { - Signaled = true; - - base.Signal(); - } - - System.CriticalSectionLock.Unlock(); - } - - public void Reset() - { - Signaled = false; - } - - public override bool IsSignaled() - { - return Signaled; + ReadableEvent = new KReadableEvent(System, this); + WritableEvent = new KWritableEvent(this); } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/KHandleEntry.cs b/Ryujinx.HLE/HOS/Kernel/KHandleEntry.cs new file mode 100644 index 000000000..9863a374b --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/KHandleEntry.cs @@ -0,0 +1,17 @@ +namespace Ryujinx.HLE.HOS.Kernel +{ + class KHandleEntry + { + public KHandleEntry Next { get; set; } + + public int Index { get; private set; } + + public ushort HandleId { get; set; } + public object Obj { get; set; } + + public KHandleEntry(int Index) + { + this.Index = Index; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/KProcessHandleTable.cs b/Ryujinx.HLE/HOS/Kernel/KProcessHandleTable.cs index db0eaa44f..682f08d4f 100644 --- a/Ryujinx.HLE/HOS/Kernel/KProcessHandleTable.cs +++ b/Ryujinx.HLE/HOS/Kernel/KProcessHandleTable.cs @@ -1,34 +1,183 @@ -using System.Collections.Generic; +using System; namespace Ryujinx.HLE.HOS.Kernel { class KProcessHandleTable { - private IdDictionary Handles; + private const int SelfThreadHandle = (0x1ffff << 15) | 0; + private const int SelfProcessHandle = (0x1ffff << 15) | 1; - public KProcessHandleTable() + private Horizon System; + + private KHandleEntry[] Table; + + private KHandleEntry TableHead; + private KHandleEntry NextFreeEntry; + + private int ActiveSlotsCount; + + private int Size; + + private ushort IdCounter; + + private object LockObj; + + public KProcessHandleTable(Horizon System, int Size = 1024) { - Handles = new IdDictionary(); + this.System = System; + this.Size = Size; + + IdCounter = 1; + + Table = new KHandleEntry[Size]; + + TableHead = new KHandleEntry(0); + + KHandleEntry Entry = TableHead; + + for (int Index = 0; Index < Size; Index++) + { + Table[Index] = Entry; + + Entry.Next = new KHandleEntry(Index + 1); + + Entry = Entry.Next; + } + + Table[Size - 1].Next = null; + + NextFreeEntry = TableHead; + + LockObj = new object(); } - public int OpenHandle(object Obj) + public KernelResult GenerateHandle(object Obj, out int Handle) { - return Handles.Add(Obj); + Handle = 0; + + lock (LockObj) + { + if (ActiveSlotsCount >= Size) + { + return KernelResult.HandleTableFull; + } + + KHandleEntry Entry = NextFreeEntry; + + NextFreeEntry = Entry.Next; + + Entry.Obj = Obj; + Entry.HandleId = IdCounter; + + ActiveSlotsCount++; + + Handle = (int)((IdCounter << 15) & (uint)0xffff8000) | Entry.Index; + + if ((short)(IdCounter + 1) >= 0) + { + IdCounter++; + } + else + { + IdCounter = 1; + } + } + + return KernelResult.Success; } - public T GetData(int Handle) + public bool CloseHandle(int Handle) { - return Handles.GetData(Handle); + if ((Handle >> 30) != 0 || + Handle == SelfThreadHandle || + Handle == SelfProcessHandle) + { + return false; + } + + int Index = (Handle >> 0) & 0x7fff; + int HandleId = (Handle >> 15); + + bool Result = false; + + lock (LockObj) + { + if (HandleId != 0 && Index < Size) + { + KHandleEntry Entry = Table[Index]; + + if (Entry.Obj != null && Entry.HandleId == HandleId) + { + Entry.Obj = null; + Entry.Next = NextFreeEntry; + + NextFreeEntry = Entry; + + ActiveSlotsCount--; + + Result = true; + } + } + } + + return Result; } - public object CloseHandle(int Handle) + public T GetObject(int Handle) { - return Handles.Delete(Handle); + int Index = (Handle >> 0) & 0x7fff; + int HandleId = (Handle >> 15); + + lock (LockObj) + { + if ((Handle >> 30) == 0 && HandleId != 0) + { + KHandleEntry Entry = Table[Index]; + + if (Entry.HandleId == HandleId && Entry.Obj is T Obj) + { + return Obj; + } + } + } + + return default(T); } - public ICollection Clear() + public KThread GetKThread(int Handle) { - return Handles.Clear(); + if (Handle == SelfThreadHandle) + { + return System.Scheduler.GetCurrentThread(); + } + else + { + return GetObject(Handle); + } + } + + public void Destroy() + { + lock (LockObj) + { + for (int Index = 0; Index < Size; Index++) + { + KHandleEntry Entry = Table[Index]; + + if (Entry.Obj != null) + { + if (Entry.Obj is IDisposable DisposableObj) + { + DisposableObj.Dispose(); + } + + Entry.Obj = null; + Entry.Next = NextFreeEntry; + + NextFreeEntry = Entry; + } + } + } } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/KReadableEvent.cs b/Ryujinx.HLE/HOS/Kernel/KReadableEvent.cs new file mode 100644 index 000000000..d43fe8249 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/KReadableEvent.cs @@ -0,0 +1,62 @@ +namespace Ryujinx.HLE.HOS.Kernel +{ + class KReadableEvent : KSynchronizationObject + { + private KEvent Parent; + + private bool Signaled; + + public KReadableEvent(Horizon System, KEvent Parent) : base(System) + { + this.Parent = Parent; + } + + public override void Signal() + { + System.CriticalSectionLock.Lock(); + + if (!Signaled) + { + Signaled = true; + + base.Signal(); + } + + System.CriticalSectionLock.Unlock(); + } + + public KernelResult Clear() + { + Signaled = false; + + return KernelResult.Success; + } + + public KernelResult ClearIfSignaled() + { + KernelResult Result; + + System.CriticalSectionLock.Lock(); + + if (Signaled) + { + Signaled = false; + + Result = KernelResult.Success; + } + else + { + Result = KernelResult.InvalidState; + } + + System.CriticalSectionLock.Unlock(); + + return Result; + } + + public override bool IsSignaled() + { + return Signaled; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/KScheduler.cs b/Ryujinx.HLE/HOS/Kernel/KScheduler.cs index f6382d05d..3cfda4197 100644 --- a/Ryujinx.HLE/HOS/Kernel/KScheduler.cs +++ b/Ryujinx.HLE/HOS/Kernel/KScheduler.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Threading; namespace Ryujinx.HLE.HOS.Kernel { @@ -35,12 +34,6 @@ namespace Ryujinx.HLE.HOS.Kernel { CoreContexts[Core] = new KCoreContext(this, CoreManager); } - - Thread PreemptionThread = new Thread(PreemptCurrentThread); - - KeepPreempting = true; - - PreemptionThread.Start(); } private void PreemptThreads() diff --git a/Ryujinx.HLE/HOS/Kernel/KWritableEvent.cs b/Ryujinx.HLE/HOS/Kernel/KWritableEvent.cs new file mode 100644 index 000000000..1721ed001 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/KWritableEvent.cs @@ -0,0 +1,22 @@ +namespace Ryujinx.HLE.HOS.Kernel +{ + class KWritableEvent + { + private KEvent Parent; + + public KWritableEvent(KEvent Parent) + { + this.Parent = Parent; + } + + public void Signal() + { + Parent.ReadableEvent.Signal(); + } + + public KernelResult Clear() + { + return Parent.ReadableEvent.Clear(); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/KernelErr.cs b/Ryujinx.HLE/HOS/Kernel/KernelErr.cs index 0749f3fd0..e0b196f41 100644 --- a/Ryujinx.HLE/HOS/Kernel/KernelErr.cs +++ b/Ryujinx.HLE/HOS/Kernel/KernelErr.cs @@ -6,6 +6,7 @@ namespace Ryujinx.HLE.HOS.Kernel public const int InvalidSize = 101; public const int InvalidAddress = 102; public const int OutOfMemory = 104; + public const int HandleTableFull = 105; public const int NoAccessPerm = 106; public const int InvalidPermission = 108; public const int InvalidMemRange = 110; diff --git a/Ryujinx.HLE/HOS/Kernel/KernelResult.cs b/Ryujinx.HLE/HOS/Kernel/KernelResult.cs new file mode 100644 index 000000000..d9cbfc673 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/KernelResult.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS.Kernel +{ + enum KernelResult + { + Success = 0, + HandleTableFull = 0xd201, + InvalidHandle = 0xe401, + InvalidState = 0xfa01 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/SvcHandler.cs b/Ryujinx.HLE/HOS/Kernel/SvcHandler.cs index a12a0ba0f..b678037b9 100644 --- a/Ryujinx.HLE/HOS/Kernel/SvcHandler.cs +++ b/Ryujinx.HLE/HOS/Kernel/SvcHandler.cs @@ -39,9 +39,6 @@ namespace Ryujinx.HLE.HOS.Kernel } } - private const uint SelfThreadHandle = 0xffff8000; - private const uint SelfProcessHandle = 0xffff8001; - private static Random Rng; public SvcHandler(Switch Device, Process Process) @@ -63,12 +60,13 @@ namespace Ryujinx.HLE.HOS.Kernel { 0x0e, SvcGetThreadCoreMask }, { 0x0f, SvcSetThreadCoreMask }, { 0x10, SvcGetCurrentProcessorNumber }, - { 0x12, SvcClearEvent }, + { 0x11, SignalEvent64 }, + { 0x12, ClearEvent64 }, { 0x13, SvcMapSharedMemory }, { 0x14, SvcUnmapSharedMemory }, { 0x15, SvcCreateTransferMemory }, { 0x16, SvcCloseHandle }, - { 0x17, SvcResetSignal }, + { 0x17, ResetSignal64 }, { 0x18, SvcWaitSynchronization }, { 0x19, SvcCancelSynchronization }, { 0x1a, SvcArbitrateLock }, @@ -88,7 +86,8 @@ namespace Ryujinx.HLE.HOS.Kernel { 0x32, SvcSetThreadActivity }, { 0x33, SvcGetThreadContext3 }, { 0x34, SvcWaitForAddress }, - { 0x35, SvcSignalToAddress } + { 0x35, SvcSignalToAddress }, + { 0x45, CreateEvent64 } }; this.Device = Device; @@ -123,17 +122,5 @@ namespace Ryujinx.HLE.HOS.Kernel throw new NotImplementedException($"0x{e.Id:x4}"); } } - - private KThread GetThread(long Tpidr, int Handle) - { - if ((uint)Handle == SelfThreadHandle) - { - return Process.GetThread(Tpidr); - } - else - { - return Process.HandleTable.GetData(Handle); - } - } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/SvcMemory.cs b/Ryujinx.HLE/HOS/Kernel/SvcMemory.cs index b9e71b183..e3c0cf5b5 100644 --- a/Ryujinx.HLE/HOS/Kernel/SvcMemory.cs +++ b/Ryujinx.HLE/HOS/Kernel/SvcMemory.cs @@ -276,7 +276,7 @@ namespace Ryujinx.HLE.HOS.Kernel return; } - KSharedMemory SharedMemory = Process.HandleTable.GetData(Handle); + KSharedMemory SharedMemory = Process.HandleTable.GetObject(Handle); if (SharedMemory == null) { @@ -348,7 +348,7 @@ namespace Ryujinx.HLE.HOS.Kernel return; } - KSharedMemory SharedMemory = Process.HandleTable.GetData(Handle); + KSharedMemory SharedMemory = Process.HandleTable.GetObject(Handle); if (SharedMemory == null) { @@ -425,9 +425,9 @@ namespace Ryujinx.HLE.HOS.Kernel KTransferMemory TransferMemory = new KTransferMemory(Position, Size); - int Handle = Process.HandleTable.OpenHandle(TransferMemory); + KernelResult Result = Process.HandleTable.GenerateHandle(TransferMemory, out int Handle); - ThreadState.X0 = 0; + ThreadState.X0 = (uint)Result; ThreadState.X1 = (ulong)Handle; } diff --git a/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs b/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs index 60ccf7f7f..8bcea5507 100644 --- a/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs +++ b/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs @@ -22,20 +22,73 @@ namespace Ryujinx.HLE.HOS.Kernel Device.System.ExitProcess(Process.ProcessId); } - private void SvcClearEvent(AThreadState ThreadState) + private void SignalEvent64(AThreadState ThreadState) { - int Handle = (int)ThreadState.X0; + ThreadState.X0 = (ulong)SignalEvent((int)ThreadState.X0); + } - //TODO: Implement events. + private KernelResult SignalEvent(int Handle) + { + KWritableEvent WritableEvent = Process.HandleTable.GetObject(Handle); - ThreadState.X0 = 0; + KernelResult Result; + + if (WritableEvent != null) + { + WritableEvent.Signal(); + + Result = KernelResult.Success; + } + else + { + Result = KernelResult.InvalidHandle; + } + + if (Result != KernelResult.Success) + { + Device.Log.PrintWarning(LogClass.KernelSvc, "Operation failed with error: " + Result + "!"); + } + + return Result; + } + + private void ClearEvent64(AThreadState ThreadState) + { + ThreadState.X0 = (ulong)ClearEvent((int)ThreadState.X0); + } + + private KernelResult ClearEvent(int Handle) + { + KernelResult Result; + + KWritableEvent WritableEvent = Process.HandleTable.GetObject(Handle); + + if (WritableEvent == null) + { + KReadableEvent ReadableEvent = Process.HandleTable.GetObject(Handle); + + Result = ReadableEvent?.Clear() ?? KernelResult.InvalidHandle; + } + else + { + Result = WritableEvent.Clear(); + } + + if (Result != KernelResult.Success) + { + Device.Log.PrintWarning(LogClass.KernelSvc, "Operation failed with error: " + Result + "!"); + } + + return Result; } private void SvcCloseHandle(AThreadState ThreadState) { int Handle = (int)ThreadState.X0; - object Obj = Process.HandleTable.CloseHandle(Handle); + object Obj = Process.HandleTable.GetObject(Handle); + + Process.HandleTable.CloseHandle(Handle); if (Obj == null) { @@ -60,24 +113,37 @@ namespace Ryujinx.HLE.HOS.Kernel ThreadState.X0 = 0; } - private void SvcResetSignal(AThreadState ThreadState) + private void ResetSignal64(AThreadState ThreadState) { - int Handle = (int)ThreadState.X0; + ThreadState.X0 = (ulong)ResetSignal((int)ThreadState.X0); + } - KEvent Event = Process.HandleTable.GetData(Handle); + private KernelResult ResetSignal(int Handle) + { + KReadableEvent ReadableEvent = Process.HandleTable.GetObject(Handle); - if (Event != null) + KernelResult Result; + + //TODO: KProcess support. + if (ReadableEvent != null) { - Event.Reset(); - - ThreadState.X0 = 0; + Result = ReadableEvent.ClearIfSignaled(); } else { - Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid event handle 0x{Handle:x8}!"); - - ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); + Result = KernelResult.InvalidHandle; } + + if (Result == KernelResult.InvalidState) + { + Device.Log.PrintDebug(LogClass.KernelSvc, "Operation failed with error: " + Result + "!"); + } + else if (Result != KernelResult.Success) + { + Device.Log.PrintWarning(LogClass.KernelSvc, "Operation failed with error: " + Result + "!"); + } + + return Result; } private void SvcGetSystemTick(AThreadState ThreadState) @@ -96,10 +162,13 @@ namespace Ryujinx.HLE.HOS.Kernel //actually exists, return error codes otherwise. KSession Session = new KSession(ServiceFactory.MakeService(System, Name), Name); - ulong Handle = (ulong)Process.HandleTable.OpenHandle(Session); + if (Process.HandleTable.GenerateHandle(Session, out int Handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } ThreadState.X0 = 0; - ThreadState.X1 = Handle; + ThreadState.X1 = (uint)Handle; } private void SvcSendSyncRequest(AThreadState ThreadState) @@ -122,7 +191,7 @@ namespace Ryujinx.HLE.HOS.Kernel byte[] MessageData = Memory.ReadBytes(MessagePtr, Size); - KSession Session = Process.HandleTable.GetData(Handle); + KSession Session = Process.HandleTable.GetObject(Handle); if (Session != null) { @@ -206,7 +275,8 @@ namespace Ryujinx.HLE.HOS.Kernel if (InfoType == 18 || InfoType == 19 || InfoType == 20 || - InfoType == 21) + InfoType == 21 || + InfoType == 22) { ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidEnumValue); @@ -287,5 +357,37 @@ namespace Ryujinx.HLE.HOS.Kernel ThreadState.X0 = 0; } + + private void CreateEvent64(AThreadState State) + { + KernelResult Result = CreateEvent(out int WEventHandle, out int REventHandle); + + State.X0 = (ulong)Result; + State.X1 = (ulong)WEventHandle; + State.X2 = (ulong)REventHandle; + } + + private KernelResult CreateEvent(out int WEventHandle, out int REventHandle) + { + KEvent Event = new KEvent(System); + + KernelResult Result = Process.HandleTable.GenerateHandle(Event.WritableEvent, out WEventHandle); + + if (Result == KernelResult.Success) + { + Result = Process.HandleTable.GenerateHandle(Event.ReadableEvent, out REventHandle); + + if (Result != KernelResult.Success) + { + Process.HandleTable.CloseHandle(WEventHandle); + } + } + else + { + REventHandle = 0; + } + + return Result; + } } } diff --git a/Ryujinx.HLE/HOS/Kernel/SvcThread.cs b/Ryujinx.HLE/HOS/Kernel/SvcThread.cs index dc296b060..d9273e23a 100644 --- a/Ryujinx.HLE/HOS/Kernel/SvcThread.cs +++ b/Ryujinx.HLE/HOS/Kernel/SvcThread.cs @@ -53,7 +53,7 @@ namespace Ryujinx.HLE.HOS.Kernel { int Handle = (int)ThreadState.X0; - KThread Thread = Process.HandleTable.GetData(Handle); + KThread Thread = Process.HandleTable.GetObject(Handle); if (Thread != null) { @@ -112,7 +112,7 @@ namespace Ryujinx.HLE.HOS.Kernel { int Handle = (int)ThreadState.X1; - KThread Thread = GetThread(ThreadState.Tpidr, Handle); + KThread Thread = Process.HandleTable.GetKThread(Handle); if (Thread != null) { @@ -138,7 +138,7 @@ namespace Ryujinx.HLE.HOS.Kernel //TODO: NPDM check. - KThread Thread = GetThread(ThreadState.Tpidr, Handle); + KThread Thread = Process.HandleTable.GetKThread(Handle); if (Thread == null) { @@ -160,7 +160,7 @@ namespace Ryujinx.HLE.HOS.Kernel Device.Log.PrintDebug(LogClass.KernelSvc, "Handle = 0x" + Handle.ToString("x8")); - KThread Thread = GetThread(ThreadState.Tpidr, Handle); + KThread Thread = Process.HandleTable.GetKThread(Handle); if (Thread != null) { @@ -178,12 +178,12 @@ namespace Ryujinx.HLE.HOS.Kernel private void SvcSetThreadCoreMask(AThreadState ThreadState) { - int ThreadHandle = (int)ThreadState.X0; + int Handle = (int)ThreadState.X0; int PrefferedCore = (int)ThreadState.X1; long AffinityMask = (long)ThreadState.X2; Device.Log.PrintDebug(LogClass.KernelSvc, - "ThreadHandle = 0x" + ThreadHandle .ToString("x8") + ", " + + "Handle = 0x" + Handle .ToString("x8") + ", " + "PrefferedCore = 0x" + PrefferedCore.ToString("x8") + ", " + "AffinityMask = 0x" + AffinityMask .ToString("x16")); @@ -219,11 +219,11 @@ namespace Ryujinx.HLE.HOS.Kernel } } - KThread Thread = GetThread(ThreadState.Tpidr, ThreadHandle); + KThread Thread = Process.HandleTable.GetKThread(Handle); if (Thread == null) { - Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{ThreadHandle:x8}!"); + Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!"); ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); @@ -249,7 +249,7 @@ namespace Ryujinx.HLE.HOS.Kernel { int Handle = (int)ThreadState.X1; - KThread Thread = GetThread(ThreadState.Tpidr, Handle); + KThread Thread = Process.HandleTable.GetKThread(Handle); if (Thread != null) { @@ -269,7 +269,7 @@ namespace Ryujinx.HLE.HOS.Kernel int Handle = (int)ThreadState.X0; bool Pause = (int)ThreadState.X1 == 1; - KThread Thread = Process.HandleTable.GetData(Handle); + KThread Thread = Process.HandleTable.GetObject(Handle); if (Thread == null) { @@ -304,7 +304,7 @@ namespace Ryujinx.HLE.HOS.Kernel long Position = (long)ThreadState.X0; int Handle = (int)ThreadState.X1; - KThread Thread = Process.HandleTable.GetData(Handle); + KThread Thread = Process.HandleTable.GetObject(Handle); if (Thread == null) { diff --git a/Ryujinx.HLE/HOS/Kernel/SvcThreadSync.cs b/Ryujinx.HLE/HOS/Kernel/SvcThreadSync.cs index 868e01729..db9f6fb48 100644 --- a/Ryujinx.HLE/HOS/Kernel/SvcThreadSync.cs +++ b/Ryujinx.HLE/HOS/Kernel/SvcThreadSync.cs @@ -1,5 +1,6 @@ using ChocolArm64.State; using Ryujinx.HLE.Logging; +using System.Collections.Generic; using static Ryujinx.HLE.HOS.ErrorCode; @@ -25,22 +26,27 @@ namespace Ryujinx.HLE.HOS.Kernel return; } - KSynchronizationObject[] SyncObjs = new KSynchronizationObject[HandlesCount]; + List SyncObjs = new List(); for (int Index = 0; Index < HandlesCount; Index++) { int Handle = Memory.ReadInt32(HandlesPtr + Index * 4); - KSynchronizationObject SyncObj = Process.HandleTable.GetData(Handle); + KSynchronizationObject SyncObj = Process.HandleTable.GetObject(Handle); - SyncObjs[Index] = SyncObj; + if (SyncObj == null) + { + break; + } + + SyncObjs.Add(SyncObj); } int HndIndex = (int)ThreadState.X1; ulong High = ThreadState.X1 & (0xffffffffUL << 32); - long Result = System.Synchronization.WaitFor(SyncObjs, Timeout, ref HndIndex); + long Result = System.Synchronization.WaitFor(SyncObjs.ToArray(), Timeout, ref HndIndex); if (Result != 0) { @@ -65,7 +71,7 @@ namespace Ryujinx.HLE.HOS.Kernel Device.Log.PrintDebug(LogClass.KernelSvc, "ThreadHandle = 0x" + ThreadHandle.ToString("x8")); - KThread Thread = Process.HandleTable.GetData(ThreadHandle); + KThread Thread = Process.HandleTable.GetKThread(ThreadHandle); if (Thread == null) { diff --git a/Ryujinx.HLE/HOS/Process.cs b/Ryujinx.HLE/HOS/Process.cs index f7ec2604c..3817f5619 100644 --- a/Ryujinx.HLE/HOS/Process.cs +++ b/Ryujinx.HLE/HOS/Process.cs @@ -71,7 +71,22 @@ namespace Ryujinx.HLE.HOS TlsPages = new List(); - HandleTable = new KProcessHandleTable(); + int HandleTableSize = 1024; + + if (MetaData != null) + { + foreach (KernelAccessControlItem Item in MetaData.ACI0.KernelAccessControl.Items) + { + if (Item.HasHandleTableSize) + { + HandleTableSize = Item.HandleTableSize; + + break; + } + } + } + + HandleTable = new KProcessHandleTable(Device.System, HandleTableSize); AppletState = new AppletStateMgr(Device.System); @@ -139,7 +154,7 @@ namespace Ryujinx.HLE.HOS return false; } - KThread MainThread = HandleTable.GetData(Handle); + KThread MainThread = HandleTable.GetKThread(Handle); if (NeedsHbAbi) { @@ -190,7 +205,7 @@ namespace Ryujinx.HLE.HOS Thread.LastPc = EntryPoint; - int Handle = HandleTable.OpenHandle(Thread); + HandleTable.GenerateHandle(Thread, out int Handle); CpuThread.ThreadState.CntfrqEl0 = TickFreq; CpuThread.ThreadState.Tpidr = Tpidr; @@ -427,13 +442,7 @@ namespace Ryujinx.HLE.HOS Disposed = true; - foreach (object Obj in HandleTable.Clear()) - { - if (Obj is KSession Session) - { - Session.Dispose(); - } - } + HandleTable.Destroy(); INvDrvServices.UnloadProcess(this); diff --git a/Ryujinx.HLE/HOS/Services/Am/ICommonStateGetter.cs b/Ryujinx.HLE/HOS/Services/Am/ICommonStateGetter.cs index 72049d6f4..4ea18d329 100644 --- a/Ryujinx.HLE/HOS/Services/Am/ICommonStateGetter.cs +++ b/Ryujinx.HLE/HOS/Services/Am/ICommonStateGetter.cs @@ -1,6 +1,7 @@ using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.Logging; +using System; using System.Collections.Generic; using static Ryujinx.HLE.HOS.ErrorCode; @@ -36,7 +37,10 @@ namespace Ryujinx.HLE.HOS.Services.Am { KEvent Event = Context.Process.AppletState.MessageEvent; - int Handle = Context.Process.HandleTable.OpenHandle(Event); + if (Context.Process.HandleTable.GenerateHandle(Event.ReadableEvent, out int Handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); @@ -103,7 +107,10 @@ namespace Ryujinx.HLE.HOS.Services.Am public long GetDefaultDisplayResolutionChangeEvent(ServiceCtx Context) { - int Handle = Context.Process.HandleTable.OpenHandle(DisplayResolutionChangeEvent); + if (Context.Process.HandleTable.GenerateHandle(DisplayResolutionChangeEvent.ReadableEvent, out int Handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); diff --git a/Ryujinx.HLE/HOS/Services/Am/IHomeMenuFunctions.cs b/Ryujinx.HLE/HOS/Services/Am/IHomeMenuFunctions.cs index 0c271796e..a476aff97 100644 --- a/Ryujinx.HLE/HOS/Services/Am/IHomeMenuFunctions.cs +++ b/Ryujinx.HLE/HOS/Services/Am/IHomeMenuFunctions.cs @@ -1,6 +1,7 @@ using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.Logging; +using System; using System.Collections.Generic; namespace Ryujinx.HLE.HOS.Services.Am @@ -34,7 +35,10 @@ namespace Ryujinx.HLE.HOS.Services.Am public long GetPopFromGeneralChannelEvent(ServiceCtx Context) { - int Handle = Context.Process.HandleTable.OpenHandle(ChannelEvent); + if (Context.Process.HandleTable.GenerateHandle(ChannelEvent.ReadableEvent, out int Handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); diff --git a/Ryujinx.HLE/HOS/Services/Am/ILibraryAppletAccessor.cs b/Ryujinx.HLE/HOS/Services/Am/ILibraryAppletAccessor.cs index a9de3ebd4..07b8d9710 100644 --- a/Ryujinx.HLE/HOS/Services/Am/ILibraryAppletAccessor.cs +++ b/Ryujinx.HLE/HOS/Services/Am/ILibraryAppletAccessor.cs @@ -1,6 +1,7 @@ using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.Logging; +using System; using System.Collections.Generic; namespace Ryujinx.HLE.HOS.Services.Am @@ -29,9 +30,12 @@ namespace Ryujinx.HLE.HOS.Services.Am public long GetAppletStateChangedEvent(ServiceCtx Context) { - StateChangedEvent.Signal(); + StateChangedEvent.ReadableEvent.Signal(); - int Handle = Context.Process.HandleTable.OpenHandle(StateChangedEvent); + if (Context.Process.HandleTable.GenerateHandle(StateChangedEvent.ReadableEvent, out int Handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); diff --git a/Ryujinx.HLE/HOS/Services/Am/ISelfController.cs b/Ryujinx.HLE/HOS/Services/Am/ISelfController.cs index fe8822735..2c1d0c3bc 100644 --- a/Ryujinx.HLE/HOS/Services/Am/ISelfController.cs +++ b/Ryujinx.HLE/HOS/Services/Am/ISelfController.cs @@ -1,6 +1,7 @@ using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.Logging; +using System; using System.Collections.Generic; namespace Ryujinx.HLE.HOS.Services.Am @@ -57,9 +58,12 @@ namespace Ryujinx.HLE.HOS.Services.Am public long GetLibraryAppletLaunchableEvent(ServiceCtx Context) { - LaunchableEvent.Signal(); + LaunchableEvent.ReadableEvent.Signal(); - int Handle = Context.Process.HandleTable.OpenHandle(LaunchableEvent); + if (Context.Process.HandleTable.GenerateHandle(LaunchableEvent.ReadableEvent, out int Handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioOut/IAudioOut.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioOut/IAudioOut.cs index 2b0b5293e..cd3d6e490 100644 --- a/Ryujinx.HLE/HOS/Services/Aud/AudioOut/IAudioOut.cs +++ b/Ryujinx.HLE/HOS/Services/Aud/AudioOut/IAudioOut.cs @@ -67,7 +67,10 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut public long RegisterBufferEvent(ServiceCtx Context) { - int Handle = Context.Process.HandleTable.OpenHandle(ReleaseEvent); + if (Context.Process.HandleTable.GenerateHandle(ReleaseEvent.ReadableEvent, out int Handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/IAudioRenderer.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/IAudioRenderer.cs index ae85bf018..85f82622f 100644 --- a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/IAudioRenderer.cs +++ b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/IAudioRenderer.cs @@ -72,7 +72,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer private void AudioCallback() { - UpdateEvent.Signal(); + UpdateEvent.ReadableEvent.Signal(); } private static T[] CreateArray(int Size) where T : new() @@ -218,7 +218,10 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer public long QuerySystemEvent(ServiceCtx Context) { - int Handle = Context.Process.HandleTable.OpenHandle(UpdateEvent); + if (Context.Process.HandleTable.GenerateHandle(UpdateEvent.ReadableEvent, out int Handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); diff --git a/Ryujinx.HLE/HOS/Services/Aud/IAudioDevice.cs b/Ryujinx.HLE/HOS/Services/Aud/IAudioDevice.cs index adecc7210..a1a228ed1 100644 --- a/Ryujinx.HLE/HOS/Services/Aud/IAudioDevice.cs +++ b/Ryujinx.HLE/HOS/Services/Aud/IAudioDevice.cs @@ -2,6 +2,7 @@ using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.Logging; +using System; using System.Collections.Generic; using System.Text; @@ -35,7 +36,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud SystemEvent = new KEvent(System); //TODO: We shouldn't be signaling this here. - SystemEvent.Signal(); + SystemEvent.ReadableEvent.Signal(); } public long ListAudioDeviceName(ServiceCtx Context) @@ -107,7 +108,10 @@ namespace Ryujinx.HLE.HOS.Services.Aud public long QueryAudioDeviceSystemEvent(ServiceCtx Context) { - int Handle = Context.Process.HandleTable.OpenHandle(SystemEvent); + if (Context.Process.HandleTable.GenerateHandle(SystemEvent.ReadableEvent, out int Handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); @@ -200,7 +204,10 @@ namespace Ryujinx.HLE.HOS.Services.Aud public long QueryAudioDeviceInputEvent(ServiceCtx Context) { - int Handle = Context.Process.HandleTable.OpenHandle(SystemEvent); + if (Context.Process.HandleTable.GenerateHandle(SystemEvent.ReadableEvent, out int Handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); @@ -211,7 +218,10 @@ namespace Ryujinx.HLE.HOS.Services.Aud public long QueryAudioDeviceOutputEvent(ServiceCtx Context) { - int Handle = Context.Process.HandleTable.OpenHandle(SystemEvent); + if (Context.Process.HandleTable.GenerateHandle(SystemEvent.ReadableEvent, out int Handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); diff --git a/Ryujinx.HLE/HOS/Services/Aud/IAudioOutManager.cs b/Ryujinx.HLE/HOS/Services/Aud/IAudioOutManager.cs index ef9250d92..44b856cda 100644 --- a/Ryujinx.HLE/HOS/Services/Aud/IAudioOutManager.cs +++ b/Ryujinx.HLE/HOS/Services/Aud/IAudioOutManager.cs @@ -150,7 +150,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud ReleaseCallback Callback = () => { - ReleaseEvent.Signal(); + ReleaseEvent.ReadableEvent.Signal(); }; IAalOutput AudioOut = Context.Device.AudioOut; diff --git a/Ryujinx.HLE/HOS/Services/Hid/IAppletResource.cs b/Ryujinx.HLE/HOS/Services/Hid/IAppletResource.cs index 012ccb405..89a17acf7 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/IAppletResource.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/IAppletResource.cs @@ -1,5 +1,6 @@ using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel; +using System; using System.Collections.Generic; namespace Ryujinx.HLE.HOS.Services.Hid @@ -24,7 +25,10 @@ namespace Ryujinx.HLE.HOS.Services.Hid public long GetSharedMemoryHandle(ServiceCtx Context) { - int Handle = Context.Process.HandleTable.OpenHandle(HidSharedMem); + if (Context.Process.HandleTable.GenerateHandle(HidSharedMem, out int Handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); diff --git a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs index b42f76fa3..e88ca7e4d 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs @@ -2,7 +2,6 @@ using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.Input; using Ryujinx.HLE.Logging; -using Ryujinx.HLE.Utilities; using System; using System.Collections.Generic; @@ -219,7 +218,10 @@ namespace Ryujinx.HLE.HOS.Services.Hid { long XpadId = Context.RequestData.ReadInt64(); - XpadIdEventHandle = Context.Process.HandleTable.OpenHandle(XpadIdEvent); + if (Context.Process.HandleTable.GenerateHandle(XpadIdEvent, out XpadIdEventHandle) == 0) + { + throw new InvalidOperationException("Out of handles!"); + } Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(XpadIdEventHandle); @@ -411,7 +413,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid SixAxisSensorFusionEnabled = Context.RequestData.ReadBoolean(); int SixAxisSensorHandle = Context.RequestData.ReadInt32(); long AppletResourceUserId = Context.RequestData.ReadInt64(); - + Context.Device.Log.PrintStub(LogClass.ServiceHid, $"Stubbed. AppletResourceUserId: {AppletResourceUserId} - " + $"SixAxisSensorHandle: {SixAxisSensorHandle} - " + $"SixAxisSensorFusionEnabled: {SixAxisSensorFusionEnabled}"); @@ -619,7 +621,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid // IsSixAxisSensorAtRest(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId) -> bool IsAsRest public long IsSixAxisSensorAtRest(ServiceCtx Context) - { + { int SixAxisSensorHandle = Context.RequestData.ReadInt32(); long AppletResourceUserId = Context.RequestData.ReadInt64(); @@ -712,7 +714,10 @@ namespace Ryujinx.HLE.HOS.Services.Hid int NpadId = Context.RequestData.ReadInt32(); long NpadStyleSet = Context.RequestData.ReadInt64(); - int Handle = Context.Process.HandleTable.OpenHandle(NpadStyleSetUpdateEvent); + if (Context.Process.HandleTable.GenerateHandle(NpadStyleSetUpdateEvent, out int Handle) == 0) + { + throw new InvalidOperationException("Out of handles!"); + } Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); @@ -1135,7 +1140,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid { int ConsoleSixAxisSensorHandle = Context.RequestData.ReadInt32(); long AppletResourceUserId = Context.RequestData.ReadInt64(); - + Context.Device.Log.PrintStub(LogClass.ServiceHid, $"Stubbed. AppletResourceUserId: {AppletResourceUserId} - " + $"ConsoleSixAxisSensorHandle: {ConsoleSixAxisSensorHandle}"); @@ -1351,7 +1356,10 @@ namespace Ryujinx.HLE.HOS.Services.Hid { int PalmaConnectionHandle = Context.RequestData.ReadInt32(); - int Handle = Context.Process.HandleTable.OpenHandle(PalmaOperationCompleteEvent); + if (Context.Process.HandleTable.GenerateHandle(PalmaOperationCompleteEvent, out int Handle) == 0) + { + throw new InvalidOperationException("Out of handles!"); + } Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); @@ -1393,7 +1401,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid int PalmaConnectionHandle = Context.RequestData.ReadInt32(); long FrModeType = Context.RequestData.ReadInt64(); - Context.Device.Log.PrintStub(LogClass.ServiceHid, $"Stubbed. PalmaConnectionHandle: {PalmaConnectionHandle} - " + + Context.Device.Log.PrintStub(LogClass.ServiceHid, $"Stubbed. PalmaConnectionHandle: {PalmaConnectionHandle} - " + $"FrModeType: {FrModeType}"); return 0; diff --git a/Ryujinx.HLE/HOS/Services/IpcService.cs b/Ryujinx.HLE/HOS/Services/IpcService.cs index 8e487d55c..e9d820001 100644 --- a/Ryujinx.HLE/HOS/Services/IpcService.cs +++ b/Ryujinx.HLE/HOS/Services/IpcService.cs @@ -132,7 +132,10 @@ namespace Ryujinx.HLE.HOS.Services { KSession Session = new KSession(Obj, Context.Session.ServiceName); - int Handle = Context.Process.HandleTable.OpenHandle(Session); + if (Context.Process.HandleTable.GenerateHandle(Session, out int Handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); } @@ -146,7 +149,7 @@ namespace Ryujinx.HLE.HOS.Services { int Handle = Context.Request.HandleDesc.ToMove[Index]; - KSession Session = Context.Process.HandleTable.GetData(Handle); + KSession Session = Context.Process.HandleTable.GetObject(Handle); return Session?.Service is T ? (T)Session.Service : null; } diff --git a/Ryujinx.HLE/HOS/Services/Nfp/IUser.cs b/Ryujinx.HLE/HOS/Services/Nfp/IUser.cs index 33f739677..72a385d2f 100644 --- a/Ryujinx.HLE/HOS/Services/Nfp/IUser.cs +++ b/Ryujinx.HLE/HOS/Services/Nfp/IUser.cs @@ -2,6 +2,7 @@ using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.Input; using Ryujinx.HLE.Logging; +using System; using System.Collections.Generic; namespace Ryujinx.HLE.HOS.Services.Nfp @@ -55,7 +56,10 @@ namespace Ryujinx.HLE.HOS.Services.Nfp { Context.Device.Log.PrintStub(LogClass.ServiceNfp, "Stubbed."); - int Handle = Context.Process.HandleTable.OpenHandle(ActivateEvent); + if (Context.Process.HandleTable.GenerateHandle(ActivateEvent.ReadableEvent, out int Handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);; @@ -66,7 +70,10 @@ namespace Ryujinx.HLE.HOS.Services.Nfp { Context.Device.Log.PrintStub(LogClass.ServiceNfp, "Stubbed."); - int Handle = Context.Process.HandleTable.OpenHandle(DeactivateEvent); + if (Context.Process.HandleTable.GenerateHandle(DeactivateEvent.ReadableEvent, out int Handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); @@ -104,7 +111,10 @@ namespace Ryujinx.HLE.HOS.Services.Nfp { Context.Device.Log.PrintStub(LogClass.ServiceNfp, "Stubbed."); - int Handle = Context.Process.HandleTable.OpenHandle(AvailabilityChangeEvent); + if (Context.Process.HandleTable.GenerateHandle(AvailabilityChangeEvent.ReadableEvent, out int Handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); diff --git a/Ryujinx.HLE/HOS/Services/Nifm/IRequest.cs b/Ryujinx.HLE/HOS/Services/Nifm/IRequest.cs index 3f4df719c..9b501d7ca 100644 --- a/Ryujinx.HLE/HOS/Services/Nifm/IRequest.cs +++ b/Ryujinx.HLE/HOS/Services/Nifm/IRequest.cs @@ -1,6 +1,7 @@ using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.Logging; +using System; using System.Collections.Generic; namespace Ryujinx.HLE.HOS.Services.Nifm @@ -48,8 +49,15 @@ namespace Ryujinx.HLE.HOS.Services.Nifm public long GetSystemEventReadableHandles(ServiceCtx Context) { - int Handle0 = Context.Process.HandleTable.OpenHandle(Event0); - int Handle1 = Context.Process.HandleTable.OpenHandle(Event1); + if (Context.Process.HandleTable.GenerateHandle(Event0.ReadableEvent, out int Handle0) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + + if (Context.Process.HandleTable.GenerateHandle(Event1.ReadableEvent, out int Handle1) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle0, Handle1); diff --git a/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs b/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs index 7d5589920..96de8cab4 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs @@ -123,7 +123,10 @@ namespace Ryujinx.HLE.HOS.Services.Nv int EventId = Context.RequestData.ReadInt32(); //TODO: Use Fd/EventId, different channels have different events. - int Handle = Context.Process.HandleTable.OpenHandle(Event); + if (Context.Process.HandleTable.GenerateHandle(Event.ReadableEvent, out int Handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); diff --git a/Ryujinx.HLE/HOS/Services/Pl/ISharedFontManager.cs b/Ryujinx.HLE/HOS/Services/Pl/ISharedFontManager.cs index 92821217b..d73adc0ef 100644 --- a/Ryujinx.HLE/HOS/Services/Pl/ISharedFontManager.cs +++ b/Ryujinx.HLE/HOS/Services/Pl/ISharedFontManager.cs @@ -1,5 +1,7 @@ using Ryujinx.HLE.HOS.Font; using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel; +using System; using System.Collections.Generic; namespace Ryujinx.HLE.HOS.Services.Pl @@ -65,7 +67,10 @@ namespace Ryujinx.HLE.HOS.Services.Pl { Context.Device.System.Font.EnsureInitialized(); - int Handle = Context.Process.HandleTable.OpenHandle(Context.Device.System.FontSharedMem); + if (Context.Process.HandleTable.GenerateHandle(Context.Device.System.FontSharedMem, out int Handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); diff --git a/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs b/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs index c56d65dbc..0c26b7d9d 100644 --- a/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs +++ b/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs @@ -1,5 +1,6 @@ using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel; +using System; using System.Collections.Generic; namespace Ryujinx.HLE.HOS.Services.Sm @@ -59,7 +60,10 @@ namespace Ryujinx.HLE.HOS.Services.Sm KSession Session = new KSession(ServiceFactory.MakeService(Context.Device.System, Name), Name); - int Handle = Context.Process.HandleTable.OpenHandle(Session); + if (Context.Process.HandleTable.GenerateHandle(Session, out int Handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); diff --git a/Ryujinx.HLE/HOS/Services/Vi/IApplicationDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/IApplicationDisplayService.cs index 542382793..33a1dee97 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/IApplicationDisplayService.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/IApplicationDisplayService.cs @@ -1,6 +1,8 @@ using ChocolArm64.Memory; using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel; using System.Collections.Generic; +using System; using System.IO; using System.Text; @@ -178,7 +180,10 @@ namespace Ryujinx.HLE.HOS.Services.Vi { string Name = GetDisplayName(Context); - int Handle = Context.Process.HandleTable.OpenHandle(Context.Device.System.VsyncEvent); + if (Context.Process.HandleTable.GenerateHandle(Context.Device.System.VsyncEvent.ReadableEvent, out int Handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); diff --git a/Ryujinx.HLE/HOS/Services/Vi/IHOSBinderDriver.cs b/Ryujinx.HLE/HOS/Services/Vi/IHOSBinderDriver.cs index d47fc30a7..09a37b0f7 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/IHOSBinderDriver.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/IHOSBinderDriver.cs @@ -29,7 +29,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi BinderEvent = new KEvent(System); - BinderEvent.Signal(); + BinderEvent.ReadableEvent.Signal(); Flinger = new NvFlinger(Renderer, BinderEvent); } @@ -77,7 +77,10 @@ namespace Ryujinx.HLE.HOS.Services.Vi int Id = Context.RequestData.ReadInt32(); uint Unk = Context.RequestData.ReadUInt32(); - int Handle = Context.Process.HandleTable.OpenHandle(BinderEvent); + if (Context.Process.HandleTable.GenerateHandle(BinderEvent.ReadableEvent, out int Handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); diff --git a/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs b/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs index dcdf5d174..c5f38211b 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs @@ -338,7 +338,7 @@ namespace Ryujinx.HLE.HOS.Services.Android { BufferQueue[Slot].State = BufferState.Free; - BinderEvent.Signal(); + BinderEvent.ReadableEvent.Signal(); WaitBufferFree.Set(); } diff --git a/Ryujinx.HLE/HOS/SystemState/AppletStateMgr.cs b/Ryujinx.HLE/HOS/SystemState/AppletStateMgr.cs index b537b06ac..274892c08 100644 --- a/Ryujinx.HLE/HOS/SystemState/AppletStateMgr.cs +++ b/Ryujinx.HLE/HOS/SystemState/AppletStateMgr.cs @@ -32,14 +32,14 @@ namespace Ryujinx.HLE.HOS.SystemState { Messages.Enqueue(Message); - MessageEvent.Signal(); + MessageEvent.ReadableEvent.Signal(); } public bool TryDequeueMessage(out MessageInfo Message) { if (Messages.Count < 2) { - MessageEvent.Reset(); + MessageEvent.ReadableEvent.Clear(); } return Messages.TryDequeue(out Message);