The Pedigree Project 0.1
TimerHandlerRegistry.h
1/*
2 * Copyright (c) 2026, Pedigree Developers
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted.
6 */
7
8#ifndef PEDIGREE_KERNEL_MACHINE_TIMERHANDLERREGISTRY_H
9#define PEDIGREE_KERNEL_MACHINE_TIMERHANDLERREGISTRY_H
10#include "pedigree/kernel/Spinlock.h"
11#include "pedigree/kernel/compiler.h"
12#include "pedigree/kernel/process/AtomicStateCleanup.h"
13#include "pedigree/kernel/process/WaitQueue.h"
14#include "pedigree/kernel/processor/types.h"
15
16#include <config.h>
17
18class TimerHandler;
19
26class EXPORTED_PUBLIC TimerHandlerRegistry {
27 public:
29
30 bool registerHandler(TimerHandler* handler);
31
41 bool unregisterHandler(TimerHandler* handler);
42
44 bool dispatch(uint64_t delta, TimerHandler* onlyHandler = nullptr);
45
47 void reset();
48
49#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
50 using HandlerPinHook = void (*)(TimerHandler*);
51 using HandlerPrePinHook = void (*)(TimerHandler*);
52 using HandlerHazardClaimHook = void (*)(TimerHandler*);
53 using HandlerAtomicDrainHook = void (*)(TimerHandler*);
54 using MutationLockHook = void (*)();
55
56 void setHandlerPinHook(HandlerPinHook hook);
57 void setHandlerPrePinHook(HandlerPrePinHook hook);
58 void setHandlerHazardClaimHook(HandlerHazardClaimHook hook);
59 void setHandlerAtomicDrainHook(HandlerAtomicDrainHook hook);
60 void withMutationLockForTest(MutationLockHook hook);
61 size_t activeDispatchCountForTest(TimerHandler* handler);
62 size_t claimedDispatchCountForTest();
63#endif
64
65 private:
66 static constexpr size_t MaxHandlerSlots = 32;
67 static constexpr size_t MaxActiveDispatches = 64;
68
69 enum class SlotMode : size_t {
70 Empty = 0,
71 Enabled,
72 Draining,
73 Deferred,
74 Retiring,
75 };
76
77 static constexpr size_t ModeBits = 3;
78 static constexpr size_t ModeMask = (1 << ModeBits) - 1;
79 static constexpr size_t SelfRemovalBit = 1 << ModeBits;
80 static constexpr size_t SynchronousDrainBit = 1 << (ModeBits + 1);
81 static constexpr size_t GenerationShift = ModeBits + 2;
82
83 struct HandlerSlot;
84
86 ActiveDispatch() : token(nullptr), generation(0), owner(nullptr), slot(nullptr) {}
87
88 void* token;
89 size_t generation;
90 void* owner;
91 HandlerSlot* slot;
92 };
93
94 struct HandlerSlot {
95 HandlerSlot() : handler(nullptr), publication(0) {}
96
97 TimerHandler* handler;
98 size_t publication;
99 };
100
102 DispatchCleanup(TimerHandlerRegistry* handlerRegistry, HandlerSlot* handlerSlot,
103 void* dispatchOwner, size_t admittedPublication)
104 : registry(handlerRegistry),
105 slot(handlerSlot),
106 owner(dispatchOwner),
107 publication(admittedPublication),
108 cleanup() {}
109
110 TimerHandlerRegistry* registry;
111 HandlerSlot* slot;
112 void* owner;
113 size_t publication;
115 };
116
117 static size_t makePublication(size_t generation, SlotMode mode, bool selfRemoval = false,
118 bool synchronousDrain = false);
119 static size_t generationOf(size_t publication);
120 static SlotMode modeOf(size_t publication);
121 static bool selfRemovalOf(size_t publication);
122 static bool synchronousDrainOf(size_t publication);
123
124 bool retireSlot(HandlerSlot& slot, size_t expectedPublication, TimerHandler* expectedHandler);
125 ActiveDispatch* publishDispatch(HandlerSlot& slot, void* owner, void* token);
126 bool unpublishDispatch(void* token, HandlerSlot& slot, size_t admittedPublication, bool required);
127 static void abandonDispatch(void* context);
128 bool hasActiveDispatch(HandlerSlot& slot) const;
129 bool findCurrentDispatch(void* owner, HandlerSlot* target, bool& callbackContext) const;
130 static void* currentDispatchOwner();
131
132 HandlerSlot m_Handlers[MaxHandlerSlots];
133 ActiveDispatch m_ActiveDispatches[MaxActiveDispatches];
134 WaitQueue m_DispatchWaiters;
135 Spinlock m_HandlerLock;
136
137#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
138 HandlerPinHook m_HandlerPinHook;
139 HandlerPrePinHook m_HandlerPrePinHook;
140 HandlerHazardClaimHook m_HandlerHazardClaimHook;
141 HandlerAtomicDrainHook m_HandlerAtomicDrainHook;
142#endif
143};
144
145#endif