20#include "SchedulerTimer.h"
21#include "pedigree/kernel/Log.h"
22#include "pedigree/kernel/compiler.h"
23#include "pedigree/kernel/machine/Machine.h"
24#include "pedigree/kernel/machine/SchedulerTimerDispatchCleanup.h"
25#include "pedigree/kernel/machine/SchedulerTimerHandler.h"
26#include "pedigree/kernel/processor/Processor.h"
28#include "IrqManager.h"
31#define ONE_SECOND 1000000000
34uint64_t HostedSchedulerTimer::nominalQuantumNs()
const {
35 return uint64_t(ONE_SECOND) / HZ;
40#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
41HostedSchedulerTimer::HardContextHook HostedSchedulerTimer::m_HardContextHook =
nullptr;
43void HostedSchedulerTimer::setHardContextHookForTest(HardContextHook hook) {
44 __atomic_store_n(&m_HardContextHook, hook, __ATOMIC_RELEASE);
47uintptr_t HostedSchedulerTimer::sourceForTest() {
48 return reinterpret_cast<uintptr_t
>(&
m_Instance);
55size_t HostedSchedulerTimer::activeDispatchesForTest() {
59bool HostedSchedulerTimer::directRoutePublishedForTest() {
60 return HostedIrqManager::schedulerIrqHandlerForTest(1) == &
m_Instance;
63bool HostedSchedulerTimer::queueTickForTest() {
64 return m_Instance.m_TickSource.queueExpirationForTest();
81 if (!m_TickSource.prepare(SIGUSR2,
this)) {
85 IrqManager& irqManager = *Machine::instance().getIrqManager();
88 m_TickSource.destroy();
94 if (!m_TickSource.arm(ONE_SECOND / HZ)) {
97 "HostedSchedulerTimer could not roll back its IRQ "
101 m_TickSource.destroy();
105 m_bInitialized =
true;
109 if (!m_bInitialized) {
112 m_bInitialized =
false;
114 if (!m_TickSource.disarm()) {
115 FATAL(
"HostedSchedulerTimer could not disarm its signal source");
120 IrqManager& irqManager = *Machine::instance().getIrqManager();
123 "HostedSchedulerTimer teardown could not remove its direct "
128 m_TickSource.destroy();
135 : m_IrqId(0), m_TickSource(), m_Handler(), m_bInitialized(false) {}
137void HostedSchedulerTimer::schedulerIrq(irq_id_t number, InterruptState& state) {
138 const siginfo_t* signalInfo =
reinterpret_cast<const siginfo_t*
>(state.getRegister(1));
139 if (number != 1 || state.getInterruptNumber() != SIGUSR2) {
143 size_t expirations = 0;
144 const HostedTickSource::TakeResult result = m_TickSource.takeExpirations(signalInfo, expirations);
145 if (result == HostedTickSource::TakeResult::NotSource) {
148 if (result == HostedTickSource::TakeResult::Invalid) {
149 FATAL_NOLOCK(
"HostedSchedulerTimer received invalid tick-source metadata");
156 constexpr uint64_t Interval = ONE_SECOND / HZ;
157 if (expirations > (~
static_cast<uint64_t
>(0) / Interval)) {
158 FATAL_NOLOCK(
"HostedSchedulerTimer elapsed-time batch overflowed");
161 const uint64_t delta =
static_cast<uint64_t
>(expirations) * Interval;
167#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
170 HardContextHook hook = __atomic_load_n(&m_HardContextHook, __ATOMIC_ACQUIRE);
175 dispatch.handler()->
timer(delta, state);
virtual ~HostedSchedulerTimer()
static HostedSchedulerTimer m_Instance
SchedulerTimerHandlerSlot m_Handler
HostedSchedulerTimer() INITIALISATION_ONLY
bool initialise() INITIALISATION_ONLY
virtual bool registerHandler(SchedulerTimerHandler *handler)
virtual bool removeHandler(SchedulerTimerHandler *handler)
virtual irq_id_t registerSchedulerIrqHandler(uint8_t irq, SchedulerIrqHandler *handler, const IrqPolicy &policy)
virtual bool unregisterSchedulerIrqHandler(irq_id_t Id, SchedulerIrqHandler *handler)
bool beginDispatch(size_t owner, DispatchGuard &guard)
bool publish(size_t owner, SchedulerTimerHandler *handler)
size_t activeDispatches() const
bool unpublish(size_t owner, SchedulerTimerHandler *handler)
virtual void timer(uint64_t delta, InterruptState &state)=0
static bool canRemoveHandlerInCurrentContext()