public KScheduler(Horizon System) { this.System = System; SchedulingData = new KSchedulingData(); CoreManager = new HleCoreManager(); CoreContexts = new KCoreContext[CpuCoresCount]; for (int Core = 0; Core < CpuCoresCount; Core++) { CoreContexts[Core] = new KCoreContext(this, CoreManager); } }
public KScheduler(Horizon system) { _system = system; SchedulingData = new KSchedulingData(); CoreManager = new HleCoreManager(); CoreContexts = new KCoreContext[CpuCoresCount]; for (int core = 0; core < CpuCoresCount; core++) { CoreContexts[core] = new KCoreContext(this, CoreManager); } }
public KScheduler() { SchedulingData = new KSchedulingData(); CoreManager = new HleCoreManager(); CoreContexts = new KCoreContext[CpuCoresCount]; for (int Core = 0; Core < CpuCoresCount; Core++) { CoreContexts[Core] = new KCoreContext(this, CoreManager); } if (!MultiCoreScheduling) { Thread PreemptionThread = new Thread(PreemptCurrentThread); KeepPreempting = true; PreemptionThread.Start(); } }
public void ContextSwitch() { lock (CoreContexts) { if (MultiCoreScheduling) { int SelectedCount = 0; for (int Core = 0; Core < KScheduler.CpuCoresCount; Core++) { KCoreContext CoreContext = CoreContexts[Core]; if (CoreContext.ContextSwitchNeeded && (CoreContext.CurrentThread?.Thread.IsCurrentThread() ?? false)) { CoreContext.ContextSwitch(); } if (CoreContext.CurrentThread?.Thread.IsCurrentThread() ?? false) { SelectedCount++; } } if (SelectedCount == 0) { CoreManager.GetThread(Thread.CurrentThread).Pause(); } else if (SelectedCount == 1) { CoreManager.GetThread(Thread.CurrentThread).Unpause(); } else { throw new InvalidOperationException("Thread scheduled in more than one core!"); } } else { KThread CurrentThread = CoreContexts[CurrentCore].CurrentThread; bool HasThreadExecuting = CurrentThread != null; if (HasThreadExecuting) { //This is not the thread that is currently executing, we need //to request an interrupt to allow safely starting another thread. if (!CurrentThread.Thread.IsCurrentThread()) { CurrentThread.Thread.RequestInterrupt(); return; } CoreManager.GetThread(CurrentThread.Thread.Work).Pause(); } //Advance current core and try picking a thread, //keep advancing if it is null. for (int Core = 0; Core < 4; Core++) { CurrentCore = (CurrentCore + 1) % CpuCoresCount; KCoreContext CoreContext = CoreContexts[CurrentCore]; CoreContext.UpdateCurrentThread(); if (CoreContext.CurrentThread != null) { CoreContext.CurrentThread.ClearExclusive(); CoreManager.GetThread(CoreContext.CurrentThread.Thread.Work).Unpause(); CoreContext.CurrentThread.Thread.Execute(); break; } } //If nothing was running before, then we are on a "external" //HLE thread, we don't need to wait. if (!HasThreadExecuting) { return; } } } CoreManager.GetThread(Thread.CurrentThread).Wait(); }
public void Leave() { if (_recursionCount == 0) { return; } bool doContextSwitch = false; if (--_recursionCount == 0) { if (_system.Scheduler.ThreadReselectionRequested) { _system.Scheduler.SelectThreads(); } Monitor.Exit(LockObj); if (_system.Scheduler.MultiCoreScheduling) { lock (_system.Scheduler.CoreContexts) { for (int core = 0; core < KScheduler.CpuCoresCount; core++) { KCoreContext coreContext = _system.Scheduler.CoreContexts[core]; if (coreContext.ContextSwitchNeeded) { CpuThread currentHleThread = coreContext.CurrentThread?.Context; if (currentHleThread == null) { //Nothing is running, we can perform the context switch immediately. coreContext.ContextSwitch(); } else if (currentHleThread.IsCurrentThread()) { //Thread running on the current core, context switch will block. doContextSwitch = true; } else { //Thread running on another core, request a interrupt. currentHleThread.RequestInterrupt(); } } } } } else { doContextSwitch = true; } } else { Monitor.Exit(LockObj); } if (doContextSwitch) { _system.Scheduler.ContextSwitch(); } }
public void Unlock() { if (RecursionCount == 0) { return; } bool DoContextSwitch = false; if (--RecursionCount == 0) { if (System.Scheduler.ThreadReselectionRequested) { System.Scheduler.SelectThreads(); } Monitor.Exit(LockObj); if (System.Scheduler.MultiCoreScheduling) { lock (System.Scheduler.CoreContexts) { for (int Core = 0; Core < KScheduler.CpuCoresCount; Core++) { KCoreContext CoreContext = System.Scheduler.CoreContexts[Core]; if (CoreContext.ContextSwitchNeeded) { AThread CurrentHleThread = CoreContext.CurrentThread?.Context; if (CurrentHleThread == null) { //Nothing is running, we can perform the context switch immediately. CoreContext.ContextSwitch(); } else if (CurrentHleThread.IsCurrentThread()) { //Thread running on the current core, context switch will block. DoContextSwitch = true; } else { //Thread running on another core, request a interrupt. CurrentHleThread.RequestInterrupt(); } } } } } else { DoContextSwitch = true; } } else { Monitor.Exit(LockObj); } if (DoContextSwitch) { System.Scheduler.ContextSwitch(); } }
private KernelResult GetInfo(uint id, int handle, long subId, out long value) { value = 0; switch (id) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 20: case 21: case 22: { if (subId != 0) { return(KernelResult.InvalidCombination); } KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess process = currentProcess.HandleTable.GetKProcess(handle); if (process == null) { return(KernelResult.InvalidHandle); } switch (id) { case 0: value = process.Capabilities.AllowedCpuCoresMask; break; case 1: value = process.Capabilities.AllowedThreadPriosMask; break; case 2: value = (long)process.MemoryManager.AliasRegionStart; break; case 3: value = (long)(process.MemoryManager.AliasRegionEnd - process.MemoryManager.AliasRegionStart); break; case 4: value = (long)process.MemoryManager.HeapRegionStart; break; case 5: value = (long)(process.MemoryManager.HeapRegionEnd - process.MemoryManager.HeapRegionStart); break; case 6: value = (long)process.GetMemoryCapacity(); break; case 7: value = (long)process.GetMemoryUsage(); break; case 12: value = (long)process.MemoryManager.GetAddrSpaceBaseAddr(); break; case 13: value = (long)process.MemoryManager.GetAddrSpaceSize(); break; case 14: value = (long)process.MemoryManager.StackRegionStart; break; case 15: value = (long)(process.MemoryManager.StackRegionEnd - process.MemoryManager.StackRegionStart); break; case 16: value = (long)process.PersonalMmHeapPagesCount * KMemoryManager.PageSize; break; case 17: if (process.PersonalMmHeapPagesCount != 0) { value = process.MemoryManager.GetMmUsedPages() * KMemoryManager.PageSize; } break; case 18: value = process.TitleId; break; case 20: value = (long)process.UserExceptionContextAddress; break; case 21: value = (long)process.GetMemoryCapacityWithoutPersonalMmHeap(); break; case 22: value = (long)process.GetMemoryUsageWithoutPersonalMmHeap(); break; } break; } case 8: { if (handle != 0) { return(KernelResult.InvalidHandle); } if (subId != 0) { return(KernelResult.InvalidCombination); } value = _system.Scheduler.GetCurrentProcess().Debug ? 1 : 0; break; } case 9: { if (handle != 0) { return(KernelResult.InvalidHandle); } if (subId != 0) { return(KernelResult.InvalidCombination); } KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); if (currentProcess.ResourceLimit != null) { KHandleTable handleTable = currentProcess.HandleTable; KResourceLimit resourceLimit = currentProcess.ResourceLimit; KernelResult result = handleTable.GenerateHandle(resourceLimit, out int resLimHandle); if (result != KernelResult.Success) { return(result); } value = (uint)resLimHandle; } break; } case 10: { if (handle != 0) { return(KernelResult.InvalidHandle); } int currentCore = _system.Scheduler.GetCurrentThread().CurrentCore; if (subId != -1 && subId != currentCore) { return(KernelResult.InvalidCombination); } value = _system.Scheduler.CoreContexts[currentCore].TotalIdleTimeTicks; break; } case 11: { if (handle != 0) { return(KernelResult.InvalidHandle); } if ((ulong)subId > 3) { return(KernelResult.InvalidCombination); } KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); value = currentProcess.RandomEntropy[subId]; break; } case 0xf0000002u: { if (subId < -1 || subId > 3) { return(KernelResult.InvalidCombination); } KThread thread = _system.Scheduler.GetCurrentProcess().HandleTable.GetKThread(handle); if (thread == null) { return(KernelResult.InvalidHandle); } KThread currentThread = _system.Scheduler.GetCurrentThread(); int currentCore = currentThread.CurrentCore; if (subId != -1 && subId != currentCore) { return(KernelResult.Success); } KCoreContext coreContext = _system.Scheduler.CoreContexts[currentCore]; long timeDelta = PerformanceCounter.ElapsedMilliseconds - coreContext.LastContextSwitchTime; if (subId != -1) { value = KTimeManager.ConvertMillisecondsToTicks(timeDelta); } else { long totalTimeRunning = thread.TotalTimeRunning; if (thread == currentThread) { totalTimeRunning += timeDelta; } value = KTimeManager.ConvertMillisecondsToTicks(totalTimeRunning); } break; } default: return(KernelResult.InvalidEnumValue); } return(KernelResult.Success); }
private KernelResult GetInfo(uint Id, int Handle, long SubId, out long Value) { Value = 0; switch (Id) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 20: case 21: case 22: { if (SubId != 0) { return(KernelResult.InvalidCombination); } KProcess CurrentProcess = System.Scheduler.GetCurrentProcess(); KProcess Process = CurrentProcess.HandleTable.GetKProcess(Handle); if (Process == null) { return(KernelResult.InvalidHandle); } switch (Id) { case 0: Value = Process.Capabilities.AllowedCpuCoresMask; break; case 1: Value = Process.Capabilities.AllowedThreadPriosMask; break; case 2: Value = (long)Process.MemoryManager.AliasRegionStart; break; case 3: Value = (long)(Process.MemoryManager.AliasRegionEnd - Process.MemoryManager.AliasRegionStart); break; case 4: Value = (long)Process.MemoryManager.HeapRegionStart; break; case 5: Value = (long)(Process.MemoryManager.HeapRegionEnd - Process.MemoryManager.HeapRegionStart); break; case 6: Value = (long)Process.GetMemoryCapacity(); break; case 7: Value = (long)Process.GetMemoryUsage(); break; case 12: Value = (long)Process.MemoryManager.GetAddrSpaceBaseAddr(); break; case 13: Value = (long)Process.MemoryManager.GetAddrSpaceSize(); break; case 14: Value = (long)Process.MemoryManager.StackRegionStart; break; case 15: Value = (long)(Process.MemoryManager.StackRegionEnd - Process.MemoryManager.StackRegionStart); break; case 16: Value = (long)Process.PersonalMmHeapPagesCount * KMemoryManager.PageSize; break; case 17: if (Process.PersonalMmHeapPagesCount != 0) { Value = Process.MemoryManager.GetMmUsedPages() * KMemoryManager.PageSize; } break; case 18: Value = Process.TitleId; break; case 20: Value = (long)Process.UserExceptionContextAddress; break; case 21: Value = (long)Process.GetMemoryCapacityWithoutPersonalMmHeap(); break; case 22: Value = (long)Process.GetMemoryUsageWithoutPersonalMmHeap(); break; } break; } case 8: { if (Handle != 0) { return(KernelResult.InvalidHandle); } if (SubId != 0) { return(KernelResult.InvalidCombination); } Value = System.Scheduler.GetCurrentProcess().Debug ? 1 : 0; break; } case 9: { if (Handle != 0) { return(KernelResult.InvalidHandle); } if (SubId != 0) { return(KernelResult.InvalidCombination); } KProcess CurrentProcess = System.Scheduler.GetCurrentProcess(); if (CurrentProcess.ResourceLimit != null) { KHandleTable HandleTable = CurrentProcess.HandleTable; KResourceLimit ResourceLimit = CurrentProcess.ResourceLimit; KernelResult Result = HandleTable.GenerateHandle(ResourceLimit, out int ResLimHandle); if (Result != KernelResult.Success) { return(Result); } Value = (uint)ResLimHandle; } break; } case 10: { if (Handle != 0) { return(KernelResult.InvalidHandle); } int CurrentCore = System.Scheduler.GetCurrentThread().CurrentCore; if (SubId != -1 && SubId != CurrentCore) { return(KernelResult.InvalidCombination); } Value = System.Scheduler.CoreContexts[CurrentCore].TotalIdleTimeTicks; break; } case 11: { if (Handle != 0) { return(KernelResult.InvalidHandle); } if ((ulong)SubId > 3) { return(KernelResult.InvalidCombination); } KProcess CurrentProcess = System.Scheduler.GetCurrentProcess(); Value = CurrentProcess.RandomEntropy[SubId]; break; } case 0xf0000002u: { if (SubId < -1 || SubId > 3) { return(KernelResult.InvalidCombination); } KThread Thread = System.Scheduler.GetCurrentProcess().HandleTable.GetKThread(Handle); if (Thread == null) { return(KernelResult.InvalidHandle); } KThread CurrentThread = System.Scheduler.GetCurrentThread(); int CurrentCore = CurrentThread.CurrentCore; if (SubId != -1 && SubId != CurrentCore) { return(KernelResult.Success); } KCoreContext CoreContext = System.Scheduler.CoreContexts[CurrentCore]; long TimeDelta = PerformanceCounter.ElapsedMilliseconds - CoreContext.LastContextSwitchTime; if (SubId != -1) { Value = KTimeManager.ConvertMillisecondsToTicks(TimeDelta); } else { long TotalTimeRunning = Thread.TotalTimeRunning; if (Thread == CurrentThread) { TotalTimeRunning += TimeDelta; } Value = KTimeManager.ConvertMillisecondsToTicks(TotalTimeRunning); } break; } default: return(KernelResult.InvalidEnumValue); } return(KernelResult.Success); }
public void ContextSwitch() { lock (CoreContexts) { if (MultiCoreScheduling) { int selectedCount = 0; for (int core = 0; core < CpuCoresCount; core++) { KCoreContext coreContext = CoreContexts[core]; if (coreContext.ContextSwitchNeeded && (coreContext.CurrentThread?.Context.IsCurrentThread() ?? false)) { coreContext.ContextSwitch(); } if (coreContext.CurrentThread?.Context.IsCurrentThread() ?? false) { selectedCount++; } } if (selectedCount == 0) { CoreManager.Reset(Thread.CurrentThread); } else if (selectedCount == 1) { CoreManager.Set(Thread.CurrentThread); } else { throw new InvalidOperationException("Thread scheduled in more than one core!"); } } else { KThread currentThread = CoreContexts[_currentCore].CurrentThread; bool hasThreadExecuting = currentThread != null; if (hasThreadExecuting) { //If this is not the thread that is currently executing, we need //to request an interrupt to allow safely starting another thread. if (!currentThread.Context.IsCurrentThread()) { currentThread.Context.RequestInterrupt(); return; } CoreManager.Reset(currentThread.Context.Work); } //Advance current core and try picking a thread, //keep advancing if it is null. for (int core = 0; core < 4; core++) { _currentCore = (_currentCore + 1) % CpuCoresCount; KCoreContext coreContext = CoreContexts[_currentCore]; coreContext.UpdateCurrentThread(); if (coreContext.CurrentThread != null) { coreContext.CurrentThread.ClearExclusive(); CoreManager.Set(coreContext.CurrentThread.Context.Work); coreContext.CurrentThread.Context.Execute(); break; } } //If nothing was running before, then we are on a "external" //HLE thread, we don't need to wait. if (!hasThreadExecuting) { return; } } } CoreManager.Wait(Thread.CurrentThread); }