21#include "pedigree/kernel/LockGuard.h"
22#include "pedigree/kernel/TargetInfo.h"
23#include "pedigree/kernel/compiler.h"
24#include "pedigree/kernel/core/SlamAllocator.h"
25#include "pedigree/kernel/machine/Machine.h"
26#include "pedigree/kernel/machine/Serial.h"
27#include "pedigree/kernel/machine/TimerHandler.h"
28#include "pedigree/kernel/process/Event.h"
29#include "pedigree/kernel/process/Scheduler.h"
30#include "pedigree/kernel/process/Thread.h"
31#include "pedigree/kernel/processor/Processor.h"
32#include "pedigree/kernel/processor/state.h"
38#define INTERVAL 1000000
42extern size_t g_AllocedPages;
44static uint64_t addAlarmDuration(uint64_t deadline,
size_t count, uint64_t multiplier) {
45 if (count > ((Time::Infinity - deadline) / multiplier)) {
46 return Time::Infinity;
48 return deadline + (count * multiplier);
53#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
54HostedTimer::AlarmSendAdmissionHook HostedTimer::m_AlarmSendAdmissionHook =
nullptr;
56bool HostedTimer::setSignalIntervalForTest(uint64_t nanoseconds) {
72 deadline = addAlarmDuration(deadline, alarmSecs, Time::Multiplier::Second);
73 deadline = addAlarmDuration(deadline, alarmUsecs, Time::Multiplier::Microsecond);
81 if ((*it)->m_pEvent == pEvent) {
95 if ((*it)->m_pEvent == pEvent) {
99 size_t alarmEndTime = alarm->m_Time;
102 if (alarmEndTime < currTime)
105 const uint64_t diff = alarmEndTime - currTime;
106 ret = diff / Time::Multiplier::Second;
107 if (diff % Time::Multiplier::Second) {
122bool HostedTimer::registerHandler(
TimerHandler* handler) {
126bool HostedTimer::unregisterHandler(
TimerHandler* handler) {
130#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
131void HostedTimer::setHandlerPinHook(HandlerPinHook hook) {
135void HostedTimer::setHandlerPrePinHook(HandlerPrePinHook hook) {
139void HostedTimer::setHandlerHazardClaimHook(HandlerHazardClaimHook hook) {
143void HostedTimer::setHandlerAtomicDrainHook(HandlerAtomicDrainHook hook) {
147void HostedTimer::withHandlerMutationLockForTest(HandlerMutationLockHook hook) {
151bool HostedTimer::dispatchHandlerForTest(
TimerHandler* handler, uint64_t delta) {
155size_t HostedTimer::activeDispatchCountForTest(
TimerHandler* handler) {
159size_t HostedTimer::claimedDispatchCountForTest() {
163void HostedTimer::setAlarmSendAdmissionHookForTest(AlarmSendAdmissionHook hook) {
164 __atomic_store_n(&m_AlarmSendAdmissionHook, hook, __ATOMIC_RELEASE);
167bool HostedTimer::alarmLockHeldForTest() {
210 clock_gettime(CLOCK_MONOTONIC, &tv);
211 return (tv.tv_sec * 1000000000ULL) + (tv.tv_nsec);
241 IrqManager& irqManager = *Machine::instance().getIrqManager();
246 "HostedTimer could not stop its unregistered bottom-half "
256 FATAL(
"HostedTimer could not stop after timer arming failed");
273 clock_gettime(CLOCK_REALTIME, &tv);
275 struct tm* t = gmtime_r(&tv.tv_sec, &conv);
284 m_Year = t->tm_year + 1900;
295 FATAL(
"HostedTimer teardown could not drain its split IRQ worker");
329 m_PendingExpirations(),
332 m_AlarmLock(false) {}
336 const siginfo_t* signalInfo =
reinterpret_cast<const siginfo_t*
>(state.getRegister(1));
337 if (number != 0 || state.getInterruptNumber() != SIGUSR1) {
338 return HardStageDisposition::NotHandled;
341 size_t expirations = 0;
342 const HostedTickSource::TakeResult result =
m_TickSource.takeExpirations(signalInfo, expirations);
343 if (result == HostedTickSource::TakeResult::NotSource) {
344 return HardStageDisposition::NotHandled;
346 if (result == HostedTickSource::TakeResult::Invalid) {
347 FATAL_NOLOCK(
"HostedTimer received invalid tick-source metadata");
348 return HardStageDisposition::Handled;
351 return HardStageDisposition::Handled;
355 FATAL_NOLOCK(
"HostedTimer expiration counter saturated");
356 return HardStageDisposition::Handled;
360 return HardStageDisposition::Deferred;
373 constexpr uint64_t MaximumDelta = ~static_cast<uint64_t>(0);
374 if (expirations > (MaximumDelta / INTERVAL)) {
375 FATAL(
"HostedTimer elapsed-time batch overflowed");
378 const uint64_t delta =
static_cast<uint64_t
>(expirations) * INTERVAL;
392 const bool elapsedSecond =
393 delta >= Time::Multiplier::Second ||
m_Nanosecond >= (Time::Multiplier::Second - delta);
404 bool bDispatched =
false;
407 if (pA->m_Time <= tickCount) {
413#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
414 AlarmSendAdmissionHook hook = __atomic_load_n(&m_AlarmSendAdmissionHook, __ATOMIC_ACQUIRE);
433 Machine::instance().getIrqManager()->
tick();
436#if MEMORY_LOGGING_ENABLED
447 pSerial->write_str(str);
bool initialise1() INITIALISATION_ONLY
virtual uint8_t getDayOfMonth()
virtual uint8_t getHour()
static HostedTimer m_Instance
void processTimerBatch(uint64_t delta)
IrqEventCounter m_PendingExpirations
HardStageDisposition hardIrq(irq_id_t number, InterruptState &state, size_t &work) override
HostedTickSource m_TickSource
void rearmIrqSources(size_t work) override
virtual void addAlarm(class Event *pEvent, size_t alarmSecs, size_t alarmUsecs=0)
virtual uint8_t getMonth()
TimerHandlerRegistry m_HandlerRegistry
virtual uint8_t getMinute()
HostedTimer() INITIALISATION_ONLY
virtual void removeAlarm(class Event *pEvent)
virtual uint64_t getTickCountNano()
void threadedIrq(size_t work) override
virtual uint8_t getSecond()
virtual void synchronise(bool tohw=false)
virtual uint64_t getTickCount()
virtual uint8_t getDayOfWeek()
bool quiesceIrqSources() override
virtual uint64_t getNanosecond()
bool recordFromInterrupt(size_t occurrences=1)
::Iterator< T, node_t > Iterator
virtual Serial * getSerial(size_t n)=0
static ProcessorInformation & information()
bool acquire(bool recurse=false, bool safe=true)
irq_id_t registerIsaSplitIrq(IrqManager &manager, uint8_t irq, const IrqPolicy &policy)
bool initialiseSplitIrq()
static constexpr size_t getPageSize() noexcept
bool sendEvent(Event *pEvent)
bool dispatch(uint64_t delta, TimerHandler *onlyHandler=nullptr)
bool unregisterHandler(TimerHandler *handler)