private bool CondVarWait( KThread WaitThread, int WaitThreadHandle, long MutexAddress, long CondVarAddress, ulong Timeout) { WaitThread.WaitHandle = WaitThreadHandle; WaitThread.MutexAddress = MutexAddress; WaitThread.CondVarAddress = CondVarAddress; lock (CondVarLock) { KThread CurrThread = Process.ThreadArbiterList; if (CurrThread != null) { bool DoInsert = CurrThread != WaitThread; while (CurrThread.NextCondVarThread != null) { if (CurrThread.NextCondVarThread.ActualPriority < WaitThread.ActualPriority) { break; } CurrThread = CurrThread.NextCondVarThread; DoInsert &= CurrThread != WaitThread; } //Only insert if the node doesn't already exist in the list. //This prevents circular references. if (DoInsert) { if (WaitThread.NextCondVarThread != null) { throw new InvalidOperationException(); } WaitThread.NextCondVarThread = CurrThread.NextCondVarThread; CurrThread.NextCondVarThread = WaitThread; } } else { Process.ThreadArbiterList = WaitThread; } } if (Timeout != ulong.MaxValue) { return(Process.Scheduler.EnterWait(WaitThread, NsTimeConverter.GetTimeMs(Timeout))); } else { return(Process.Scheduler.EnterWait(WaitThread)); } }
private void SvcWaitSynchronization(AThreadState ThreadState) { long HandlesPtr = (long)ThreadState.X1; int HandlesCount = (int)ThreadState.X2; ulong Timeout = ThreadState.X3; KThread 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(LogClass.KernelSvc, $"Tried to WaitSynchronization on invalid handle 0x{Handle:x8}!"); ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); return; } Handles[Index] = SyncObj.WaitEvent; } Process.Scheduler.Suspend(CurrThread.ProcessorId); int HandleIndex; ulong Result = 0; if (Timeout != ulong.MaxValue) { HandleIndex = WaitHandle.WaitAny(Handles, NsTimeConverter.GetTimeMs(Timeout)); if (HandleIndex == WaitHandle.WaitTimeout) { Result = MakeError(ErrorModule.Kernel, KernelErr.Timeout); } } else { HandleIndex = WaitHandle.WaitAny(Handles); } Process.Scheduler.Resume(CurrThread); ThreadState.X0 = Result; if (Result == 0) { ThreadState.X1 = (ulong)HandleIndex; } }
private void SvcSleepThread(AThreadState ThreadState) { ulong Ns = ThreadState.X0; KThread CurrThread = Process.GetThread(ThreadState.Tpidr); if (Ns == 0) { Process.Scheduler.Yield(CurrThread); } else { Process.Scheduler.Suspend(CurrThread.ProcessorId); Thread.Sleep(NsTimeConverter.GetTimeMs(Ns)); Process.Scheduler.Resume(CurrThread); } }
private void SvcSleepThread(AThreadState ThreadState) { ulong TimeoutNs = ThreadState.X0; KThread CurrThread = Process.GetThread(ThreadState.Tpidr); if (TimeoutNs == 0) { Process.Scheduler.SetReschedule(CurrThread.ActualCore); } else { Process.Scheduler.Suspend(CurrThread); Thread.Sleep(NsTimeConverter.GetTimeMs(TimeoutNs)); Process.Scheduler.Resume(CurrThread); } }
private bool CondVarWait( KThread WaitThread, int WaitThreadHandle, long MutexAddress, long CondVarAddress, ulong Timeout) { WaitThread.WaitHandle = WaitThreadHandle; WaitThread.MutexAddress = MutexAddress; WaitThread.CondVarAddress = CondVarAddress; lock (Process.ThreadArbiterList) { WaitThread.CondVarSignaled = false; Process.ThreadArbiterList.Add(WaitThread); } Ns.Log.PrintDebug(LogClass.KernelSvc, "Entering wait state..."); if (Timeout != ulong.MaxValue) { Process.Scheduler.EnterWait(WaitThread, NsTimeConverter.GetTimeMs(Timeout)); lock (Process.ThreadArbiterList) { if (!WaitThread.CondVarSignaled) { Process.ThreadArbiterList.Remove(WaitThread); return(false); } } } else { Process.Scheduler.EnterWait(WaitThread); } return(true); }
private void SvcWaitSynchronization(AThreadState ThreadState) { long HandlesPtr = (long)ThreadState.X1; int HandlesCount = (int)ThreadState.X2; ulong Timeout = ThreadState.X3; Ns.Log.PrintDebug(LogClass.KernelSvc, "HandlesPtr = " + HandlesPtr.ToString("x16") + ", " + "HandlesCount = " + HandlesCount.ToString("x8") + ", " + "Timeout = " + Timeout.ToString("x16")); if ((uint)HandlesCount > 0x40) { ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.CountOutOfRange); return; } KThread CurrThread = Process.GetThread(ThreadState.Tpidr); WaitHandle[] Handles = new WaitHandle[HandlesCount + 1]; for (int Index = 0; Index < HandlesCount; Index++) { int Handle = Memory.ReadInt32(HandlesPtr + Index * 4); KSynchronizationObject SyncObj = Process.HandleTable.GetData <KSynchronizationObject>(Handle); if (SyncObj == null) { Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid handle 0x{Handle:x8}!"); ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); return; } Handles[Index] = SyncObj.WaitEvent; } using (AutoResetEvent WaitEvent = new AutoResetEvent(false)) { if (!SyncWaits.TryAdd(CurrThread, WaitEvent)) { throw new InvalidOperationException(); } Handles[HandlesCount] = WaitEvent; Process.Scheduler.Suspend(CurrThread); int HandleIndex; ulong Result = 0; if (Timeout != ulong.MaxValue) { HandleIndex = WaitHandle.WaitAny(Handles, NsTimeConverter.GetTimeMs(Timeout)); } else { HandleIndex = WaitHandle.WaitAny(Handles); } if (HandleIndex == WaitHandle.WaitTimeout) { Result = MakeError(ErrorModule.Kernel, KernelErr.Timeout); } else if (HandleIndex == HandlesCount) { Result = MakeError(ErrorModule.Kernel, KernelErr.Canceled); } SyncWaits.TryRemove(CurrThread, out _); Process.Scheduler.Resume(CurrThread); ThreadState.X0 = Result; if (Result == 0) { ThreadState.X1 = (ulong)HandleIndex; } } }