public KScheduler(KernelContext context) { _context = context; 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 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) { 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); }
public void Leave() { if (_recursionCount == 0) { return; } bool doContextSwitch = false; if (--_recursionCount == 0) { if (_context.Scheduler.ThreadReselectionRequested) { _context.Scheduler.SelectThreads(); } Monitor.Exit(LockObj); if (_context.Scheduler.MultiCoreScheduling) { lock (_context.Scheduler.CoreContexts) { for (int core = 0; core < KScheduler.CpuCoresCount; core++) { KCoreContext coreContext = _context.Scheduler.CoreContexts[core]; if (coreContext.ContextSwitchNeeded) { KThread currentThread = coreContext.CurrentThread; if (currentThread == null) { // Nothing is running, we can perform the context switch immediately. coreContext.ContextSwitch(); } else if (currentThread.IsCurrentHostThread()) { // Thread running on the current core, context switch will block. doContextSwitch = true; } else { // Thread running on another core, request a interrupt. currentThread.Context.RequestInterrupt(); } } } } } else { doContextSwitch = true; } } else { Monitor.Exit(LockObj); } if (doContextSwitch) { _context.Scheduler.ContextSwitch(); } }