The Pedigree Project 0.1
eventfd-syscalls.cc
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, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 */
8
9#include "eventfd-syscalls.h"
10#include "pedigree/kernel/LockGuard.h"
11#include "pedigree/kernel/syscallError.h"
12#include "pedigree/kernel/utilities/SharedPointer.h"
13#include "pedigree/kernel/utilities/assert.h"
14
15#include <fcntl.h>
16
17#include "modules/subsys/posix/FileDescriptor.h"
18#include "modules/subsys/posix/PosixSubsystem.h"
19
20namespace {
21constexpr uint64_t MaximumCounter = ~static_cast<uint64_t>(0) - 1;
22
23void setWaitError(ConditionVariable::Error error) {
24 if (error == ConditionVariable::Interrupted || error == ConditionVariable::TerminationDeferred) {
25 SYSCALL_ERROR(Interrupted);
26 } else {
27 SYSCALL_ERROR(BadFileDescriptor);
28 }
29}
30} // namespace
31
32EventFd::EventFd(uint64_t initialValue, bool semaphoreMode)
34 m_Lock(),
35 m_Readers(),
36 m_Writers(),
37 m_Counter(initialValue),
38 m_WriteGeneration(0),
39 m_Generations(),
40 m_DescriptorOwners(0),
41 m_SemaphoreMode(semaphoreMode),
42 m_DescriptorAdmissionOpen(true) {}
43
44EventFd::~EventFd() {
45 assert(!m_DescriptorOwners);
47}
48
49int EventFd::readValue(uint64_t& value, bool canBlock) {
50 m_Lock.acquire();
51 while (!m_Counter) {
52 if (!canBlock) {
53 m_Lock.release();
54 SYSCALL_ERROR(NoMoreProcesses);
55 return -1;
56 }
57
58 ConditionVariable::Error error = ConditionVariable::NoError;
59 if (!m_Readers.wait(m_Lock, error)) {
61 m_Lock.release();
62 }
63 setWaitError(error);
64 return -1;
65 }
66 }
67
68 const bool wasWritable = m_Counter < MaximumCounter;
69 if (m_SemaphoreMode) {
70 value = 1;
71 --m_Counter;
72 } else {
73 value = m_Counter;
74 m_Counter = 0;
75 }
76 if (!wasWritable) {
77 ++m_Generations.write;
78 }
79 m_Lock.release();
80
81 m_Writers.broadcast();
82 notifyReadiness(ReadyRead | ReadyWrite);
83 return static_cast<int>(sizeof(value));
84}
85
86int EventFd::writeValue(uint64_t value, bool canBlock) {
87 if (value == ~static_cast<uint64_t>(0)) {
88 SYSCALL_ERROR(InvalidArgument);
89 return -1;
90 }
91
92 m_Lock.acquire();
93 while (value > MaximumCounter - m_Counter) {
94 if (!canBlock) {
95 m_Lock.release();
96 SYSCALL_ERROR(NoMoreProcesses);
97 return -1;
98 }
99
100 ConditionVariable::Error error = ConditionVariable::NoError;
101 if (!m_Writers.wait(m_Lock, error)) {
103 m_Lock.release();
104 }
105 setWaitError(error);
106 return -1;
107 }
108 }
109
110 const bool wasReadable = m_Counter != 0;
111 m_Counter += value;
112 if (!wasReadable && m_Counter) {
113 ++m_Generations.read;
114 }
115 m_WriteGeneration += 1;
116 m_Lock.release();
117
118 m_Readers.broadcast();
119 notifyReadiness(ReadyRead | ReadyWrite);
120 return static_cast<int>(sizeof(value));
121}
122
124 LockGuard<Mutex> guard(m_Lock);
125 ReadyMask ready = ReadyNone;
126 if (m_Counter) {
127 ready |= ReadyRead;
128 }
129 if (m_Counter < MaximumCounter) {
130 ready |= ReadyWrite;
131 }
132 return ready;
133}
134
136 LockGuard<Mutex> guard(m_Lock);
137 return m_Generations;
138}
139
140uint64_t EventFd::writeGeneration() const {
141 return m_WriteGeneration.value();
142}
143
145 LockGuard<Mutex> guard(m_Lock);
146 if (!m_DescriptorAdmissionOpen) {
147 return false;
148 }
149 ++m_DescriptorOwners;
150 return true;
151}
152
153void EventFd::removeDescriptorOwner() {
154 LockGuard<Mutex> guard(m_Lock);
155 assert(m_DescriptorOwners);
156 --m_DescriptorOwners;
157 if (!m_DescriptorOwners) {
158 m_DescriptorAdmissionOpen = false;
159 }
160}
161
162int posix_eventfd(unsigned int initialValue) {
163 return posix_eventfd2(initialValue, 0);
164}
165
166int posix_eventfd2(unsigned int initialValue, int flags) {
167 constexpr int AllowedFlags =
168 LinuxEventFd::Semaphore | LinuxEventFd::NonBlock | LinuxEventFd::CloseOnExec;
169 if (flags & ~AllowedFlags) {
170 SYSCALL_ERROR(InvalidArgument);
171 return -1;
172 }
173
174 const size_t fd = getAvailableDescriptor();
175 const int descriptorFlags = flags & LinuxEventFd::CloseOnExec ? FD_CLOEXEC : 0;
176 const int statusFlags = O_RDWR | (flags & LinuxEventFd::NonBlock ? O_NONBLOCK : 0);
177 FileDescriptor* descriptor = new FileDescriptor(nullptr, 0, fd, descriptorFlags, statusFlags);
178 descriptor->setEventFdImpl(
179 SharedPointer<EventFd>(new EventFd(initialValue, flags & LinuxEventFd::Semaphore)));
180 addDescriptor(static_cast<int>(fd), descriptor);
181 return static_cast<int>(fd);
182}
MUST_USE_RESULT bool wait(Mutex &mutex, Time::Timestamp &timeout, Error &error, WaitQueue::StackDiscardCleanup onStackDiscard=nullptr, void *stackDiscardContext=nullptr)
static bool mutexAcquired(Error error)
uint64_t writeGeneration() const
ReadinessGenerations readinessGenerations() override
int readValue(uint64_t &value, bool canBlock)
int writeValue(uint64_t value, bool canBlock)
MUST_USE_RESULT bool addDescriptorOwner()
ReadyMask queryReady()
void setEventFdImpl(const SharedPointer< EventFd > &implementation)
void notifyReadiness(ReadyMask mask)
Definition Readiness.cc:201
void closeReadiness(ReadyMask mask=ReadyInvalid|ReadyHangup)
Definition Readiness.cc:208
void release(size_t n=1)
Definition Semaphore.cc:546
bool acquire(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
Definition Semaphore.cc:352