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])
78 void refresh(uint64_t generation) {
80 for (
size_t i = 0; i < LinuxTimerFd::MaximumObjects; ++i) {
95 timer->service(generation);
106 Timer* m_Source =
nullptr;
115TimerFd::TimerFd(
int clock)
121 m_ClockGeneration(posix_clock_change_generation()),
122 m_DescriptorOwners(0),
125 m_CancelOnSet(false),
126 m_CancelPending(false),
128 m_AdmissionOpen(true) {}
131 assert(!m_DescriptorOwners);
135bool TimerFd::readable()
const {
136 return m_Counter || m_CancelWake;
140 return m_State.realtime ? clock.realtime : clock.monotonic;
144 if (clock.generation > m_ClockGeneration) {
145 m_ClockGeneration = clock.generation;
147 m_CancelPending =
true;
149 ++m_Generations.read;
152 if (m_State.armed && now(clock) >= m_State.deadline) {
153 m_State.armed =
false;
155 m_Counter = addExpirations(m_Counter, 1);
156 ++m_Generations.read;
161 if (!m_Expired || !state.interval)
165 const uint64_t expired = PosixTimerState::advance(state, current);
168 return addExpirations(m_Counter - 1, expired);
171void TimerFd::changed() {
176void TimerFd::service(uint64_t generation) {
183 if (!m_AdmissionOpen || (generation && generation <= m_ClockGeneration)) {
187 const uint64_t oldGeneration = m_Generations.read;
188 update(posix_clock_snapshot());
189 const bool notify = oldGeneration != m_Generations.read;
195int TimerFd::readToUser(
void* buffer,
size_t count,
bool canBlock) {
196 return readWithCopy(count, canBlock, copyRead, buffer);
199int TimerFd::readWithCopy(
size_t count,
bool canBlock, PosixDescriptorReadCopy copy,
201 if (count <
sizeof(uint64_t)) {
202 SYSCALL_ERROR(InvalidArgument);
209 if (!m_AdmissionOpen) {
211 SYSCALL_ERROR(BadFileDescriptor);
214 clock = posix_clock_snapshot();
216 if (readable() || (!canBlock && m_CancelOnSet && m_CancelPending))
220 SYSCALL_ERROR(NoMoreProcesses);
223 ConditionVariable::Error error = ConditionVariable::NoError;
224 if (!m_Readers.
wait(m_Lock, error)) {
227 if (error == ConditionVariable::Interrupted ||
228 error == ConditionVariable::TerminationDeferred)
229 SYSCALL_ERROR(Interrupted);
231 SYSCALL_ERROR(BadFileDescriptor);
235 if (m_CancelOnSet && m_CancelPending) {
236 m_CancelPending =
false;
237 m_CancelWake =
false;
242 SYSCALL_ERROR(Cancelled);
247 const uint64_t value = forward(next, now(clock));
248 if (value && !copy(context, &value,
sizeof(value))) {
251 SYSCALL_ERROR(BadAddress);
259 return value ?
sizeof(value) : 0;
262int TimerFd::configure(
int flags, Time::Timestamp value, Time::Timestamp interval,
void* previous) {
265 if (!m_AdmissionOpen) {
267 SYSCALL_ERROR(BadFileDescriptor);
274 forward(old, now(clock));
279 SYSCALL_ERROR(BadAddress);
283 m_CancelOnSet = m_Clock == ClockRealtime && (flags & LinuxTimerFd::Absolute) &&
284 (flags & LinuxTimerFd::CancelOnSet);
285 const bool cancelled = value && m_CancelOnSet && m_CancelPending;
287 m_CancelPending =
false;
288 m_CancelWake =
false;
289 m_ClockGeneration = clock.generation;
292 m_State.realtime = m_Clock == ClockRealtime && (flags & LinuxTimerFd::Absolute);
293 m_State.interval = interval;
295 flags & LinuxTimerFd::Absolute ? value : PosixTimerState::add(now(clock), value);
296 m_State.armed = value != 0;
301 SYSCALL_ERROR(Cancelled);
307int TimerFd::getTime(
void* value) {
310 if (!m_AdmissionOpen) {
312 SYSCALL_ERROR(BadFileDescriptor);
318 const uint64_t counter = forward(next, now(clock));
323 SYSCALL_ERROR(BadAddress);
334ReadyMask TimerFd::queryReady() {
336 if (!m_AdmissionOpen)
337 return ReadyInvalid | ReadyHangup;
338 return readable() ? ReadyRead : ReadyNone;
343 return m_Generations;
346bool TimerFd::addDescriptorOwner() {
349 if (!m_AdmissionOpen)
351 ++m_DescriptorOwners;
355void TimerFd::removeDescriptorOwner() {
358 assert(m_DescriptorOwners);
359 const bool last = !--m_DescriptorOwners;
361 m_AdmissionOpen =
false;
362 m_State.armed =
false;
363 ++m_Generations.hangup;
367 timerService.remove(
this);
373int posix_timerfd_create(
int clock,
int flags) {
374 if ((clock != ClockRealtime && clock != ClockMonotonic) ||
375 (flags & ~(LinuxTimerFd::NonBlock | LinuxTimerFd::CloseOnExec))) {
376 SYSCALL_ERROR(InvalidArgument);
381 if (!timerService.add(timer))
383 const size_t fd = getAvailableDescriptor();
384 const int descriptorFlags = flags & LinuxTimerFd::CloseOnExec ? FD_CLOEXEC : 0;
385 const int statusFlags = O_RDWR | (flags & LinuxTimerFd::NonBlock ? O_NONBLOCK : 0);
386 auto* descriptor =
new FileDescriptor(
nullptr, 0, fd, descriptorFlags, statusFlags);
387 descriptor->setTimerFdImpl(timer);
388 addDescriptor(
static_cast<int>(fd), descriptor);
389 return static_cast<int>(fd);
392int posix_timerfd_settime(
int fd,
int flags,
const void* newValue,
void* oldValue) {
395 SYSCALL_ERROR(BadAddress);
398 Time::Timestamp value, interval;
399 if ((flags & ~(LinuxTimerFd::Absolute | LinuxTimerFd::CancelOnSet)) ||
400 !PosixTimerState::decode(requested.value, value) ||
401 !PosixTimerState::decode(requested.interval, interval)) {
402 SYSCALL_ERROR(InvalidArgument);
406 if (!acquireDescriptor(fd, descriptor)) {
407 SYSCALL_ERROR(BadFileDescriptor);
412 SYSCALL_ERROR(InvalidArgument);
415 return timer->configure(flags, value, interval, oldValue);
418int posix_timerfd_gettime(
int fd,
void* value) {
420 if (!acquireDescriptor(fd, descriptor)) {
421 SYSCALL_ERROR(BadFileDescriptor);
426 SYSCALL_ERROR(InvalidArgument);
429 return timer->getTime(value);
432void posix_timerfd_clock_changed(uint64_t generation) {
433 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
void EXPORTED_PUBLIC panic(const char *msg) NORETURN