24#include "pedigree/kernel/LockGuard.h"
25#include "pedigree/kernel/Log.h"
26#include "pedigree/kernel/Metrics.h"
27#include "pedigree/kernel/process/PerProcessorScheduler.h"
28#include "pedigree/kernel/process/Process.h"
29#include "pedigree/kernel/process/ProcessorThreadAllocator.h"
30#include "pedigree/kernel/process/RoundRobinCoreAllocator.h"
31#include "pedigree/kernel/process/Scheduler.h"
32#include "pedigree/kernel/processor/Processor.h"
33#include "pedigree/kernel/processor/ProcessorInformation.h"
34#include "pedigree/kernel/utilities/Iterator.h"
35#include "pedigree/kernel/utilities/Vector.h"
36#include "pedigree/kernel/utilities/assert.h"
37#include "pedigree/kernel/utilities/utility.h"
41#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
43Scheduler::GenericThreadStatusHook g_GenericThreadStatusHook =
nullptr;
49#define SCHEDULER_HAS_SAFE_SPINLOCKS true
54#define SCHEDULER_HAS_RECURSIVE_SPINLOCKS true
56Scheduler::ProcessLease::ProcessLease() : m_pProcess(nullptr), m_TerminationDeferral(false) {}
58Scheduler::ProcessLease::ProcessLease(
Process* process)
59 : m_pProcess(process), m_TerminationDeferral(process != nullptr) {}
61Scheduler::ProcessLease::ProcessLease(ProcessLease&& other) noexcept
62 : m_pProcess(other.m_pProcess),
63 m_TerminationDeferral(pedigree_std::move(other.m_TerminationDeferral)) {
64 other.m_pProcess =
nullptr;
67Scheduler::ProcessLease::~ProcessLease() {
73 if (other.m_pProcess) {
74 m_TerminationDeferral = pedigree_std::move(other.m_TerminationDeferral);
77 m_pProcess = other.m_pProcess;
78 other.m_pProcess =
nullptr;
89void Scheduler::ProcessLease::reset() {
101 m_UserNanoseconds(0),
102 m_KernelNanoseconds(0),
103 m_IdleNanoseconds(0),
115 FATAL(
"Processor topology exceeds the affinity mask capacity.");
117 ProcessorThreadAllocator::instance().
setAlgorithm(pRoundRobin);
129 auto thisScheduler = &((*it)->getScheduler());
135 pRoundRobin->initialise(procList);
144 if (!pThread->m_Placement.migratable) {
146 const size_t cpu = PPSched.logicalCpu();
147 pThread->m_Placement.allowed.set(cpu == ~
size_t(0) ?
Processor::index() : cpu);
156 pPpSched->removeThread(pThread);
166 return pPpSched != 0;
171 if (__atomic_load_n(&it.key()->m_ActiveSyscalls[service], __ATOMIC_SEQ_CST)) {
182 assert(
id < 0x3FFFFFFF);
220 bool removed =
false;
224 if (*it == pProcess) {
237 Metrics::increment(Metrics::Counter::Yield);
244 assert(count <= CpuAffinityMask::MaximumCpus);
245 for (
size_t cpu = 0; cpu < count; ++cpu)
250size_t Scheduler::affinityBytes() {
251 return ((
Processor::getCount() + CpuAffinityMask::WordBits - 1) / CpuAffinityMask::WordBits) *
252 sizeof(
unsigned long);
257 return information ? &information->getScheduler() :
nullptr;
265 thread->
setCpuId(scheduler.m_PhysicalCpu);
298 return pResult !=
nullptr;
314 return pResult !=
nullptr;
326 if (*it == expected) {
337 return pResult !=
nullptr;
345 if (candidate->
getId() == id) {
356 return pResult !=
nullptr;
359bool Scheduler::acquireProcessByUserspaceId(ProcessLease& lease,
size_t id,
362 auto owner = current && current->getParent()->pidNamespace()
363 ? current->getParent()->pidNamespace()
364 : Process::rootPidNamespace();
382 lease = ProcessLease(pResult);
383 return pResult !=
nullptr;
386bool Scheduler::acquireNextProcess(ProcessLease& lease,
size_t afterId) {
392 if (candidate->
getId() > afterId && (!result || candidate->
getId() < result->
getId())) {
399 afterId = result->
getId();
403 lease = ProcessLease(result);
404 return result !=
nullptr;
411 auto owner = current && current->getParent()->pidNamespace()
412 ? current->getParent()->pidNamespace()
413 : Process::rootPidNamespace();
418 ProcessLease process;
419 while (acquireNextProcess(process, after)) {
420 after = process->
getId();
421 if (process->
getUserspaceId(space) && process->acquireThreadByUserspaceId(lease,
id, space)) {
431 while (afterId <
id) {
436 const size_t processId = process->
getId();
437 if (processId > afterId && processId <=
id &&
438 (!candidate || processId < candidate->getId())) {
443 afterId = candidate->
getId();
455 if (process && process->acquireThreadByTaskId(lease,
id)) {
466 bool present =
false;
469 if (*it == expected) {
479 const WaitQueue::WakeReason reason = guard.waitForCompletion(
480 WaitQueue::Channel(expected), Thread::ProcessWait,
reinterpret_cast<uintptr_t
>(expected));
487 size_t childIndex = 0;
491 if (pProcess && pProcess->
getParent() == pParent) {
492 if (childIndex == n) {
503void Scheduler::threadStatusChanged(
Thread* pThread) {
504#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
505 GenericThreadStatusHook hook = __atomic_load_n(&g_GenericThreadStatusHook, __ATOMIC_ACQUIRE);
513 pSched->threadStatusChanged(pThread);
516#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
517void Scheduler::setGenericThreadStatusHook(GenericThreadStatusHook hook) {
518 __atomic_store_n(&g_GenericThreadStatusHook, hook, __ATOMIC_RELEASE);
::Iterator< T, node_t > Iterator
size_t getUserspaceId() const
bool beginExternalLease()
void closeExternalLeaseAdmission()
void drainDeferredTimeAccounting()
static ProcessorInformation & information()
static Vector< ProcessorInformation * > m_ProcessorInformation
static ProcessorInformation * informationAt(size_t cpu)
void setAlgorithm(ThreadToCoreAllocationAlgorithm *pAlgorithm)
Sets the algorithm to use for allocating threads to cores.
This class manages how processes and threads are scheduled across processors.
MUST_USE_RESULT bool acquireFirstProcessOfType(ProcessLease &lease, Process::ProcessType type)
static Scheduler m_Instance
List< Process *, 0 > m_Processes
bool hasActiveSyscallLocked(Service_t service) const
Process * getChildProcess(Process *pParent, size_t n)
void drainDeferredTimeAccounting()
void releaseProcessLease(Process *process)
MUST_USE_RESULT bool acquireProcessById(ProcessLease &lease, size_t id)
void removeThread(Thread *pThread)
static Scheduler & instance()
size_t reserveProcessId()
bool initialise(Process *pKernelProcess)
MUST_USE_RESULT bool acquireProcess(ProcessLease &lease, size_t n)
Atomic< size_t > m_NextPid
void waitUntilProcessRemoved(Process *expected)
bool threadInSchedule(Thread *pThread)
MUST_USE_RESULT bool acquireThreadByTaskId(Process::ThreadLease &lease, size_t id)
void addThread(Thread *pThread, PerProcessorScheduler &PPSched)
Tree< PerProcessorScheduler *, List< Thread * > * > m_PTMap
Tree< Thread *, PerProcessorScheduler * > m_TPMap
WaitQueue m_ProcessRemovalWaiters
Process * m_pKernelProcess
void addProcess(Process *pProcess)
PerProcessorScheduler * m_pBspScheduler
void removeProcess(Process *pProcess)
bool acquire(bool recurse=false, bool safe=true)
void setScheduler(class PerProcessorScheduler *pScheduler)
class PerProcessorScheduler * getScheduler() const
void remove(const K &key)
E lookup(const K &key) const
void insert(const K &key, const E &value)
A vector / dynamic array.
Iterator erase(Iterator &Iter)
void pushBack(const T &value)
void pushBack(const T &value)