22 #include "pedigree/kernel/process/PerProcessorScheduler.h" 23 #include "pedigree/kernel/Atomic.h" 24 #include "pedigree/kernel/Log.h" 25 #include "pedigree/kernel/Spinlock.h" 26 #include "pedigree/kernel/Subsystem.h" 27 #include "pedigree/kernel/machine/Machine.h" 28 #include "pedigree/kernel/machine/SchedulerTimer.h" 29 #include "pedigree/kernel/panic.h" 30 #include "pedigree/kernel/process/Event.h" 31 #include "pedigree/kernel/process/Process.h" 32 #include "pedigree/kernel/process/RoundRobin.h" 33 #include "pedigree/kernel/process/SchedulingAlgorithm.h" 34 #include "pedigree/kernel/process/Thread.h" 35 #include "pedigree/kernel/processor/PhysicalMemoryManager.h" 36 #include "pedigree/kernel/processor/Processor.h" 37 #include "pedigree/kernel/processor/ProcessorInformation.h" 38 #include "pedigree/kernel/processor/VirtualAddressSpace.h" 39 #include "pedigree/kernel/processor/state.h" 40 #include "pedigree/kernel/utilities/utility.h" 43 #include "pedigree/kernel/debugger/commands/LocksCommand.h" 47 : m_pSchedulingAlgorithm(0), m_NewThreadDataLock(false),
48 m_NewThreadDataCondition(), m_NewThreadData(), m_pIdleThread(0)
56 PerProcessorScheduler::~PerProcessorScheduler()
75 pInstance->m_NewThreadDataLock.
acquire();
78 if (!pInstance->m_NewThreadData.
count())
81 pInstance->m_NewThreadDataCondition.
wait(
82 pInstance->m_NewThreadDataLock);
86 void *p = pInstance->m_NewThreadData.
popFront();
95 <<
" does not match current scheduler in processorAddThread!");
101 if (!(pData->pThread->
getStatus() == Thread::Running ||
102 pData->pThread->
getStatus() == Thread::Ready))
104 pInstance->m_NewThreadData.
pushBack(p);
111 if (pData->useSyscallState)
113 pInstance->
addThread(pData->pThread, pData->state);
118 pData->pThread, pData->pStartFunction, pData->pParam,
119 pData->bUsermode, pData->pStack);
142 panic(
"No scheduler timer present.");
148 reinterpret_cast<void *
>(
this), 0,
false,
true);
161 FATAL(
"Missing a current thread in PerProcessorScheduler::schedule!");
173 if (pNextThread == 0)
175 bool needsIdle =
false;
178 if (nextStatus != Thread::Ready)
202 if (m_pIdleThread == 0)
204 FATAL(
"No idle thread available, and the current thread is " 205 "leaving the ready state!");
209 pNextThread = m_pIdleThread;
216 pNextThread = pNewThread;
219 if (pNextThread == pNewThread)
220 WARNING(
"scheduler: next thread IS new thread");
222 if (pNextThread != pCurrentThread)
226 if (pCurrentThread != m_pIdleThread)
233 (pNextThread->
getStateLevel() ==
reinterpret_cast<uintptr_t
>(pLock)))
235 "STATE LEVEL = LOCK PASSED TO SCHEDULER: " 237 <<
reinterpret_cast<uintptr_t
>(pLock) <<
"!");
266 if (pLock->m_bInterrupts)
267 bWasInterrupts =
true;
274 FATAL(
"Lock checker disallowed this reschedule.");
278 #ifdef SYSTEM_REQUIRES_ATOMIC_CONTEXT_SWITCH 280 Processor::switchState(
281 bWasInterrupts, pCurrentThread->
state(), pNextThread->
state(),
282 &pCurrentThread->
getLock().m_Atom.m_Atom);
305 pNextThread->
state(), &pCurrentThread->
getLock().m_Atom.m_Atom);
350 if (!va.
isMapped(reinterpret_cast<void *>(handlerAddress)))
353 "checkEventState: Handler address " << handlerAddress
361 SchedulerState &oldState = pThread->
pushState();
363 physical_uintptr_t page;
365 va.
getMapping(reinterpret_cast<void *>(handlerAddress), page, flags);
370 reinterpret_cast<void *>(userStack - pageSz), page, flags);
371 if (userStack == 0 || (flags & VirtualAddressSpace::KernelMode))
374 pThread->getStateUserStack();
378 pThread->setStateUserStack(stateStack);
383 if (!va.
isMapped(adjust_pointer(stateStack->getTop(), -pageSz)))
391 pThread->setStateUserStack(stateStack);
395 userStack =
reinterpret_cast<uintptr_t
>(stateStack->getTop());
399 va.
getMapping(reinterpret_cast<void *>(userStack), page, flags);
400 if (flags & VirtualAddressSpace::KernelMode)
403 "User stack for event in checkEventState is the kernel's!");
419 if (!va.
isMapped(reinterpret_cast<void *>(addr)))
424 panic(
"checkEventState: Out of memory!");
429 pEvent->
serialize(reinterpret_cast<uint8_t *>(addr));
431 #ifndef SYSTEM_REQUIRES_ATOMIC_CONTEXT_SWITCH 443 if (flags & VirtualAddressSpace::KernelMode)
445 void (*fn)(size_t) =
reinterpret_cast<void (*)(
size_t)
>(handlerAddress);
452 else if (userStack != 0)
456 #ifdef SYSTEM_REQUIRES_ATOMIC_CONTEXT_SWITCH 457 Processor::saveAndJumpUser(
459 handlerAddress, addr);
481 bool bUsermode,
void *pStack)
485 pThread->
getStatus() == Thread::Sleeping)
488 pData->pThread = pThread;
489 pData->pStartFunction = pStartFunction;
490 pData->pParam = pParam;
491 pData->bUsermode = bUsermode;
492 pData->pStack = pStack;
493 pData->useSyscallState =
false;
495 m_NewThreadDataLock.acquire();
496 m_NewThreadData.pushBack(pData);
497 m_NewThreadDataLock.release();
499 m_NewThreadDataCondition.signal();
521 if (pCurrentThread != m_pIdleThread)
523 pCurrentThread->
setStatus(Thread::Ready);
529 reinterpret_cast<uintptr_t>(kernelStack));
536 if (pThread->
getLock().m_bInterrupts)
537 bWasInterrupts =
true;
538 bool bWas = pThread->
getLock().acquired();
540 pThread->
getLock().m_Atom.m_Atom = 1;
552 FATAL(
"Lock checker disallowed this reschedule.");
556 #ifdef SYSTEM_REQUIRES_ATOMIC_CONTEXT_SWITCH 560 Processor::saveAndJumpUser(
561 bWasInterrupts, pCurrentThread->
state(),
562 &pCurrentThread->
getLock().m_Atom.m_Atom,
563 reinterpret_cast<uintptr_t
>(pStartFunction),
564 reinterpret_cast<uintptr_t>(pStack),
565 reinterpret_cast<uintptr_t
>(pParam));
569 Processor::saveAndJumpKernel(
570 bWasInterrupts, pCurrentThread->
state(),
571 &pCurrentThread->
getLock().m_Atom.m_Atom,
572 reinterpret_cast<uintptr_t
>(pStartFunction),
573 reinterpret_cast<uintptr_t>(pStack),
574 reinterpret_cast<uintptr_t
>(pParam));
576 #else // SYSTEM_REQUIRES_ATOMIC_CONTEXT_SWITCH 590 &pCurrentThread->
getLock().m_Atom.m_Atom,
591 reinterpret_cast<uintptr_t
>(pStartFunction),
592 reinterpret_cast<uintptr_t>(pStack),
593 reinterpret_cast<uintptr_t
>(pParam));
599 &pCurrentThread->
getLock().m_Atom.m_Atom,
600 reinterpret_cast<uintptr_t
>(pStartFunction),
601 reinterpret_cast<uintptr_t>(pStack),
602 reinterpret_cast<uintptr_t
>(pParam));
604 #endif // SYSTEM_REQUIRES_ATOMIC_CONTEXT_SWITCH 611 pThread->
getStatus() == Thread::Sleeping)
614 pData->pThread = pThread;
615 pData->useSyscallState =
true;
616 pData->state = state;
620 m_NewThreadDataLock.acquire();
621 m_NewThreadData.pushBack(pData);
622 m_NewThreadDataLock.release();
624 m_NewThreadDataCondition.signal();
645 if (pCurrentThread != m_pIdleThread)
647 pCurrentThread->
setStatus(Thread::Ready);
653 reinterpret_cast<uintptr_t>(kernelStack));
660 if (pThread->
getLock().m_bInterrupts)
661 bWasInterrupts =
true;
662 bool bWas = pThread->
getLock().acquired();
664 pThread->
getLock().m_Atom.m_Atom = 1;
674 FATAL(
"Lock checker disallowed this reschedule.");
679 uintptr_t kStack =
reinterpret_cast<uintptr_t
>(pThread->
getKernelStack());
680 kStack -=
sizeof(SyscallState);
682 reinterpret_cast<void *>(kStack), reinterpret_cast<void *>(&state),
683 sizeof(SyscallState));
686 SyscallState &newState = *
reinterpret_cast<SyscallState *
>(kStack);
691 #ifdef SYSTEM_REQUIRES_ATOMIC_CONTEXT_SWITCH 693 NOTICE(
"restoring (new) syscall state");
694 Processor::switchState(
695 bWasInterrupts, pCurrentThread->
state(), newState,
696 &pCurrentThread->
getLock().m_Atom.m_Atom);
729 FATAL(
"Lock checker disallowed this reschedule.");
736 FATAL(
"Lock checker disallowed this reschedule.");
745 if (pNextThread == 0 && m_pIdleThread == 0)
748 panic(
"Attempting to kill only thread on this processor!");
750 else if (pNextThread == 0)
752 pNextThread = m_pIdleThread;
755 if (pNextThread != pThread)
762 reinterpret_cast<uintptr_t>(kernelStack));
771 pThread, pNextThread->
state(), pLock ? &pLock->m_Atom.m_Atom : 0);
774 void PerProcessorScheduler::deleteThread(
Thread *pThread)
782 void PerProcessorScheduler::removeThread(
Thread *pThread)
793 if (pThread->hasEvents())
809 schedule(Thread::Sleeping, 0, pLock);
814 #ifdef ARM_BEAGLE // Timer at 1 tick per ms, we want to run every 100 ms 816 if ((m_TickCount % 100) == 0)
830 void PerProcessorScheduler::threadStatusChanged(
Thread *pThread)
835 void PerProcessorScheduler::setIdle(
Thread *pThread)
837 m_pIdleThread = pThread;
void sleep(Spinlock *pLock=0)
void pushBack(const T &value)
static int processorAddThread(void *instance) NORETURN
static size_t getPageSize() PURE
void setScheduler(class PerProcessorScheduler *pScheduler)
static void restoreState(SchedulerState &state, volatile uintptr_t *pLock=0) NORETURN
static PhysicalMemoryManager & instance()
static bool getInterrupts()
void popState(bool clean=true)
static uintptr_t getTrampoline()
SchedulerState & pushState()
virtual size_t serialize(uint8_t *pBuffer)=0
bool acquire(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
virtual void getMapping(void *virtualAddress, physical_uintptr_t &physicalAddress, size_t &flags)=0
virtual void threadStatusChanged(Thread *pThread)=0
void checkEventState(uintptr_t userStack)
static void setTlsBase(uintptr_t newBase)
static void deleteThreadThenRestoreState(Thread *pThread, SchedulerState &newState, volatile uintptr_t *pLock=0) NORETURN
static void jumpKernel(volatile uintptr_t *pLock, uintptr_t address, uintptr_t stack, uintptr_t p1=0, uintptr_t p2=0, uintptr_t p3=0, uintptr_t p4=0) NORETURN
virtual Thread * getNext(Thread *pCurrentThread)=0
virtual physical_uintptr_t allocatePage(size_t pageConstraints=0)=0
virtual bool isMapped(void *virtualAddress)=0
virtual void addThread(Thread *pThread)=0
virtual bool map(physical_uintptr_t physicalAddress, void *virtualAddress, size_t flags)=0
size_t getStateLevel() const
void initialise(Thread *pThread)
virtual Stack * allocateStack()=0
bool acquire(bool recurse=false, bool safe=true)
bool lockReleased(const Spinlock *pLock, size_t nCpu=~0U)
static ProcessorInformation & information()
static void switchAddressSpace(VirtualAddressSpace &AddressSpace)
void timer(uint64_t delta, InterruptState &state)
void addThread(Thread *pThread, Thread::ThreadStartFunc pStartFunction, void *pParam, bool bUsermode, void *pStack)
static const size_t Write
uintptr_t getHandlerAddress()
bool sendEvent(Event *pEvent)
static const size_t KernelMode
void killCurrentThread(Spinlock *pLock=0) NORETURN
virtual void exit(int code)=0
virtual void removeThread(Thread *pThread)=0
static bool saveState(SchedulerState &state)
static void jumpUser(volatile uintptr_t *pLock, uintptr_t address, uintptr_t stack, uintptr_t p1=0, uintptr_t p2=0, uintptr_t p3=0, uintptr_t p4=0) NORETURN
void recordTime(bool bUserspace)
static void setInterrupts(bool bEnable)
static uintptr_t getHandlerBuffer()
Process * getParent() const
bool checkSchedule(size_t nCpu=~0U)
VirtualAddressSpace * getAddressSpace()
void eventHandlerReturned() NORETURN
virtual SchedulerTimer * getSchedulerTimer()=0
virtual bool isDeletable()
int(* ThreadStartFunc)(void *)
void trackTime(bool bUserspace)
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
SchedulingAlgorithm * m_pSchedulingAlgorithm
UnwindType getUnwindState()
class PerProcessorScheduler * getScheduler() const
void schedule(Thread::Status nextStatus=Thread::Ready, Thread *pNewThread=0, Spinlock *pLock=0)
WaitResult wait(Mutex &mutex, Time::Timestamp &timeout)