10#include "pedigree/kernel/LockGuard.h"
11#include "pedigree/kernel/Log.h"
12#include "pedigree/kernel/process/Mutex.h"
13#include "pedigree/kernel/process/OperationBarrier.h"
14#include "pedigree/kernel/utilities/List.h"
15#include "pedigree/kernel/utilities/assert.h"
16#include "pedigree/kernel/utilities/utility.h"
20size_t fileEventSubscriptions = 0;
26 : m_Interest(interest), m_pObserver(observer), m_Notifications() {}
29 if (!m_Notifications.isClosedAndDrained()) {
34 bool interestedIn(FileEventMask mask)
const {
35 return (mask & m_Interest) != 0;
38 FileEventMask interest()
const {
46 void notifyAdmitted(
const FileEvent& event) {
48 m_Notifications.
leave();
51 void closeAdmission() {
52 m_Notifications.
close();
62 FileEventMask m_Interest;
73 if (m_Targets.
count()) {
74 FATAL(
"FileEventState destroyed with live subscriptions.");
83 if (m_NextSequence == ~
size_t(0) || !m_Targets.
tryPushBack(target))
85 target->sequence = m_NextSequence++;
86 __atomic_store_n(&m_Interest, m_Interest | target->interest(), __ATOMIC_RELEASE);
87 __atomic_add_fetch(&fileEventSubscriptions,
size_t(1), __ATOMIC_RELEASE);
94 for (
auto it = m_Targets.
begin(); it != m_Targets.
end(); ++it) {
97 FileEventMask interest = 0;
99 for (
const auto& remaining : m_Targets) {
100 interest |= remaining->interest();
103 __atomic_store_n(&m_Interest, interest, __ATOMIC_RELEASE);
104 __atomic_sub_fetch(&fileEventSubscriptions,
size_t(1), __ATOMIC_RELEASE);
112 bool hasTargets(FileEventMask mask)
const {
113 return (__atomic_load_n(&m_Interest, __ATOMIC_ACQUIRE) & mask) != 0;
121 if (!m_Open || !m_Targets.
count())
125 boundary = m_NextSequence - 1;
134 for (
const auto& target : m_Targets) {
135 if (target->sequence > after && target->sequence <= boundary &&
136 target->interestedIn(event.mask) && target->admit()) {
138 after = target->sequence;
145 selected->notifyAdmitted(event);
149 void beginClose(
const FileEvent* finalEvent =
nullptr) {
156 __atomic_store_n(&m_Interest, FileEventMask(0), __ATOMIC_RELEASE);
159 const bool admitted = m_ClosingPublication.
tryEnter();
161 m_ClosingPublication.
close();
162 m_Publications.
close();
163 boundary = m_NextSequence - 1;
168 bool deliver =
false;
171 for (
const auto& target : m_Targets) {
172 if (target->sequence > after && target->sequence <= boundary) {
174 after = target->sequence;
175 deliver = finalEvent && target->interestedIn(finalEvent->mask) && target->admit();
176 target->closeAdmission();
184 selected->notifyAdmitted(*finalEvent);
186 m_ClosingPublication.
leave();
195 m_ClosingPublication.
wait();
196 m_Publications.
wait();
202 for (
const auto& target : m_Targets) {
203 if (target->sequence > after) {
205 after = target->sequence;
220 FileEventMask m_Interest = 0;
221 size_t m_NextSequence = 1;
226FileEventSubscription::FileEventSubscription() : m_State(), m_Target(), m_Observer() {}
229 : m_State(pedigree_std::move(other.m_State)),
230 m_Target(pedigree_std::move(other.m_Target)),
231 m_Observer(pedigree_std::move(other.m_Observer)) {}
233FileEventSubscription::~FileEventSubscription() {
238 if (
this != &other) {
240 m_State = pedigree_std::move(other.m_State);
241 m_Target = pedigree_std::move(other.m_Target);
242 m_Observer = pedigree_std::move(other.m_Observer);
247FileEventSubscription::operator bool()
const {
248 return static_cast<bool>(m_State) &&
static_cast<bool>(m_Target);
251void FileEventSubscription::reset() {
254 if (state && target) {
255 state->remove(target);
262FileEventSource::FileEventSource() : m_FileEventState(new
FileEventState) {}
264FileEventSource::~FileEventSource() {
268bool FileEventSource::subscribeFileEvents(FileEventMask interest,
271 subscription.reset();
272 if (!interest || !observer) {
277 if (!target || !m_FileEventState)
279 subscription.m_State = m_FileEventState;
280 subscription.m_Target = target;
281 subscription.m_Observer = observer;
282 if (!m_FileEventState->add(target)) {
283 subscription.reset();
290 if (hasFileEventObservers(event.mask)) {
292 state->notify(event);
297 return __atomic_load_n(&fileEventSubscriptions, __ATOMIC_ACQUIRE) != 0;
300bool FileEventSource::hasFileEventObservers(FileEventMask mask)
const {
301 return m_FileEventState && m_FileEventState->hasTargets(mask);
305 if (event.mask && m_FileEventState) {
307 state->beginClose(&event);
312void FileEventSource::closeFileEvents() {
321 if (m_FileEventState)
322 m_FileEventState->beginClose(&event);
325void FileEventSource::drainFileEvents() {
326 if (m_FileEventState)
327 m_FileEventState->drain();
330void InodeEventSource::publish(
const FileEvent& event) {
334void InodeEventSource::beginRetirement() {
virtual void fileEvent(const FileEvent &event)=0
void notifyFileEvent(const FileEvent &event)
void beginFinalFileEvent(const FileEvent &event)
void notifyFinalFileEvent(const FileEvent &event)
static bool anyFileEventObservers()
MUST_USE_RESULT bool tryAcquire(Lease &lease)
MUST_USE_RESULT bool tryEnter()
Iterator erase(Iterator &Iter)
bool tryPushBack(const T &value)