2#include "pedigree/kernel/LockGuard.h"
3#include "pedigree/kernel/machine/Machine.h"
4#include "pedigree/kernel/machine/Timer.h"
5#include "pedigree/kernel/machine/TimerHandler.h"
6#include "pedigree/kernel/panic.h"
7#include "pedigree/kernel/process/TerminationDeferral.h"
8#include "pedigree/kernel/processor/Processor.h"
9#include "pedigree/kernel/syscallError.h"
10#include "pedigree/kernel/utilities/assert.h"
14#include "FileDescriptor.h"
15#include "PosixSubsystem.h"
16#include "clock-syscalls.h"
17#include "timerfd-syscalls.h"
20constexpr int ClockRealtime = 0, ClockMonotonic = 1;
22uint64_t addExpirations(uint64_t counter, uint64_t added) {
23 return added > ~uint64_t(0) - counter ? ~uint64_t(0) : counter + added;
26bool copyRead(
void* context,
const void* value,
size_t count) {
34 if (m_Source && !m_Source->unregisterHandler(
this))
35 panic(
"timerfd callback could not be drained");
40 size_t slot = LinuxTimerFd::MaximumObjects;
41 for (
size_t i = 0; i < LinuxTimerFd::MaximumObjects; ++i)
46 if (slot == LinuxTimerFd::MaximumObjects) {
47 SYSCALL_ERROR(TooManyOpenFiles);
52 if (!source || !source->registerHandler(
this)) {
53 SYSCALL_ERROR(OutOfMemory);
58 m_Timers[slot] =
timer;
68 for (
auto& entry : m_Timers)
69 if (entry.get() ==
timer) {
70 retired = pedigree_std::move(entry);
73 while (m_End && !m_Timers[m_End - 1])
84 Time::Timestamp next = 0;
85 for (
size_t i = 0; i < m_End; ++i) {
89 Time::Timestamp deadline = 0;
90 if (!
timer->m_Lock.tryAcquire()) {
91 deadline = PosixTimerState::add(clock.monotonic, Time::Multiplier::Millisecond);
93 if (
timer->m_AdmissionOpen)
95 PosixTimerState::monotonicDeadline(
timer->m_State, clock.realtime, clock.monotonic);
96 timer->m_Lock.release();
98 if (deadline && (!next || deadline < next))
102 panic(
"timerfd service could not arm its callback");
105 void refresh(uint64_t generation) {
107 for (
size_t i = 0; i < LinuxTimerFd::MaximumObjects; ++i) {
123 timer->service(generation);
135 Timer* m_Source =
nullptr;
144TimerFd::TimerFd(
int clock)
150 m_ClockGeneration(posix_clock_change_generation()),
151 m_DescriptorOwners(0),
154 m_CancelOnSet(false),
155 m_CancelPending(false),
157 m_AdmissionOpen(true) {}
160 assert(!m_DescriptorOwners);
164bool TimerFd::readable()
const {
165 return m_Counter || m_CancelWake;
169 return m_State.realtime ? clock.realtime : clock.monotonic;
173 if (clock.generation > m_ClockGeneration) {
174 m_ClockGeneration = clock.generation;
176 m_CancelPending =
true;
178 ++m_Generations.read;
181 if (m_State.armed && now(clock) >= m_State.deadline) {
182 m_State.armed =
false;
184 m_Counter = addExpirations(m_Counter, 1);
185 ++m_Generations.read;
190 if (!m_Expired || !state.interval)
194 const uint64_t expired = PosixTimerState::advance(state, current);
197 return addExpirations(m_Counter - 1, expired);
200void TimerFd::changed() {
205void TimerFd::service(uint64_t generation) {
212 if (!m_AdmissionOpen || (generation && generation <= m_ClockGeneration)) {
216 const uint64_t oldGeneration = m_Generations.read;
217 update(posix_clock_snapshot());
218 const bool notify = oldGeneration != m_Generations.read;
224int TimerFd::readToUser(
void* buffer,
size_t count,
bool canBlock) {
225 return readWithCopy(count, canBlock, copyRead, buffer);
228int TimerFd::readWithCopy(
size_t count,
bool canBlock, PosixDescriptorReadCopy copy,
230 if (count <
sizeof(uint64_t)) {
231 SYSCALL_ERROR(InvalidArgument);
238 if (!m_AdmissionOpen) {
240 SYSCALL_ERROR(BadFileDescriptor);
243 clock = posix_clock_snapshot();
245 if (readable() || (!canBlock && m_CancelOnSet && m_CancelPending))
249 SYSCALL_ERROR(NoMoreProcesses);
252 ConditionVariable::Error error = ConditionVariable::NoError;
253 if (!m_Readers.
wait(m_Lock, error)) {
256 if (error == ConditionVariable::Interrupted ||
257 error == ConditionVariable::TerminationDeferred)
258 SYSCALL_ERROR(Interrupted);
260 SYSCALL_ERROR(BadFileDescriptor);
264 if (m_CancelOnSet && m_CancelPending) {
265 m_CancelPending =
false;
266 m_CancelWake =
false;
271 SYSCALL_ERROR(Cancelled);
276 const uint64_t value = forward(next, now(clock));
277 if (value && !copy(context, &value,
sizeof(value))) {
280 SYSCALL_ERROR(BadAddress);
287 timerService.rearm();
289 return value ?
sizeof(value) : 0;
292int TimerFd::configure(
int flags, Time::Timestamp value, Time::Timestamp interval,
void* previous) {
295 if (!m_AdmissionOpen) {
297 SYSCALL_ERROR(BadFileDescriptor);
304 forward(old, now(clock));
309 SYSCALL_ERROR(BadAddress);
313 m_CancelOnSet = m_Clock == ClockRealtime && (flags & LinuxTimerFd::Absolute) &&
314 (flags & LinuxTimerFd::CancelOnSet);
315 const bool cancelled = value && m_CancelOnSet && m_CancelPending;
317 m_CancelPending =
false;
318 m_CancelWake =
false;
319 m_ClockGeneration = clock.generation;
322 m_State.realtime = m_Clock == ClockRealtime && (flags & LinuxTimerFd::Absolute);
323 m_State.interval = interval;
325 flags & LinuxTimerFd::Absolute ? value : PosixTimerState::add(now(clock), value);
326 m_State.armed = value != 0;
329 timerService.rearm();
332 SYSCALL_ERROR(Cancelled);
338int TimerFd::getTime(
void* value) {
341 if (!m_AdmissionOpen) {
343 SYSCALL_ERROR(BadFileDescriptor);
349 const uint64_t counter = forward(next, now(clock));
354 SYSCALL_ERROR(BadAddress);
361 timerService.rearm();
366ReadyMask TimerFd::queryReady() {
368 if (!m_AdmissionOpen)
369 return ReadyInvalid | ReadyHangup;
370 return readable() ? ReadyRead : ReadyNone;
375 return m_Generations;
378bool TimerFd::addDescriptorOwner() {
381 if (!m_AdmissionOpen)
383 ++m_DescriptorOwners;
387void TimerFd::removeDescriptorOwner() {
390 assert(m_DescriptorOwners);
391 const bool last = !--m_DescriptorOwners;
393 m_AdmissionOpen =
false;
394 m_State.armed =
false;
395 ++m_Generations.hangup;
399 timerService.remove(
this);
405int posix_timerfd_create(
int clock,
int flags) {
406 if ((clock != ClockRealtime && clock != ClockMonotonic) ||
407 (flags & ~(LinuxTimerFd::NonBlock | LinuxTimerFd::CloseOnExec))) {
408 SYSCALL_ERROR(InvalidArgument);
413 if (!timerService.add(timer))
415 const size_t fd = getAvailableDescriptor();
416 const int descriptorFlags = flags & LinuxTimerFd::CloseOnExec ? FD_CLOEXEC : 0;
417 const int statusFlags = O_RDWR | (flags & LinuxTimerFd::NonBlock ? O_NONBLOCK : 0);
418 auto* descriptor =
new FileDescriptor(
nullptr, 0, fd, descriptorFlags, statusFlags);
419 descriptor->setTimerFdImpl(timer);
420 addDescriptor(
static_cast<int>(fd), descriptor);
421 return static_cast<int>(fd);
424int posix_timerfd_settime(
int fd,
int flags,
const void* newValue,
void* oldValue) {
427 SYSCALL_ERROR(BadAddress);
430 Time::Timestamp value, interval;
431 if ((flags & ~(LinuxTimerFd::Absolute | LinuxTimerFd::CancelOnSet)) ||
432 !PosixTimerState::decode(requested.value, value) ||
433 !PosixTimerState::decode(requested.interval, interval)) {
434 SYSCALL_ERROR(InvalidArgument);
438 if (!acquireDescriptor(fd, descriptor)) {
439 SYSCALL_ERROR(BadFileDescriptor);
444 SYSCALL_ERROR(InvalidArgument);
447 return timer->configure(flags, value, interval, oldValue);
450int posix_timerfd_gettime(
int fd,
void* value) {
452 if (!acquireDescriptor(fd, descriptor)) {
453 SYSCALL_ERROR(BadFileDescriptor);
458 SYSCALL_ERROR(InvalidArgument);
461 return timer->getTime(value);
464void posix_timerfd_clock_changed(uint64_t generation) {
465 timerService.refresh(generation);
MUST_USE_RESULT bool wait(Mutex &mutex, Time::Timestamp &timeout, Error &error, WaitQueue::StackDiscardCleanup onStackDiscard=nullptr, void *stackDiscardContext=nullptr)
static bool mutexAcquired(Error error)
virtual Timer * getTimer()=0
static bool copyFromUser(void *destination, const void *source, size_t count, size_t elementSize=1)
static bool copyToUser(void *destination, const void *source, size_t count, size_t elementSize=1)
static bool inDeviceHardIrq()
void notifyReadiness(ReadyMask mask)
void closeReadiness(ReadyMask mask=ReadyInvalid|ReadyHangup)
bool tryAcquire(size_t n=1)
bool acquire(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
void timer(uint64_t) override
ReadinessGenerations readinessGenerations() override
virtual bool supportsDeadlines() const
virtual bool armHandler(TimerHandler *, uint64_t)
void EXPORTED_PUBLIC panic(const char *msg) NORETURN