SNode.C
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages Concepts
EventMultiplexer.cpp
Go to the documentation of this file.
1/*
2 * SNode.C - A Slim Toolkit for Network Communication
3 * Copyright (C) Volker Christian <me@vchrist.at>
4 * 2020, 2021, 2022, 2023, 2024, 2025
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published
8 * by the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20/*
21 * MIT License
22 *
23 * Permission is hereby granted, free of charge, to any person obtaining a copy
24 * of this software and associated documentation files (the "Software"), to deal
25 * in the Software without restriction, including without limitation the rights
26 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27 * copies of the Software, and to permit persons to whom the Software is
28 * furnished to do so, subject to the following conditions:
29 *
30 * The above copyright notice and this permission notice shall be included in
31 * all copies or substantial portions of the Software.
32 *
33 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
39 * THE SOFTWARE.
40 */
41
42#include "core/EventMultiplexer.h"
43
44#include "core/DescriptorEventPublisher.h"
45#include "core/DescriptorEventReceiver.h"
46#include "core/DynamicLoader.h"
47#include "core/Event.h"
48#include "core/TimerEventPublisher.h"
49
50#ifndef DOXYGEN_SHOULD_SKIP_THIS
51
52#include "utils/Timeval.h"
53
54#include <algorithm>
55#include <cerrno>
56#include <numeric>
57#include <utility>
58
59#endif /* DOXYGEN_SHOULD_SKIP_THIS */
60
61namespace core {
62
69
71 for (DescriptorEventPublisher* descriptorEventPublisher : descriptorEventPublishers) {
72 delete descriptorEventPublisher;
73 }
75 }
76
78 return *descriptorEventPublishers[dispType];
79 }
80
84
85 void EventMultiplexer::span(Event* event) {
86 eventQueue.insert(event);
87 }
88
90 eventQueue.remove(event);
91 }
92
93 TickStatus EventMultiplexer::tick(const utils::Timeval& tickTimeOut, const sigset_t& sigMask) {
94 const utils::Timeval currentTime = utils::Timeval::currentTime();
95
96 int activeDescriptorCount = 0;
97
98 const TickStatus tickStatus = waitForEvents(tickTimeOut, currentTime, sigMask, activeDescriptorCount);
99
100 if (tickStatus == TickStatus::SUCCESS) {
101 spanActiveEvents(currentTime, activeDescriptorCount);
102 executeEventQueue(currentTime);
103 checkTimedOutEvents(currentTime);
104 releaseExpiredResources(currentTime);
105 }
106
107 return tickStatus;
108 }
109
110 void EventMultiplexer::signal(int sigNum) {
111 for (DescriptorEventPublisher* const descriptorEventPublisher : descriptorEventPublishers) {
112 descriptorEventPublisher->signal(sigNum);
113 }
115
117 }
118
120 for (DescriptorEventPublisher* const descriptorEventPublisher : descriptorEventPublishers) {
121 descriptorEventPublisher->disable();
122 }
124
126 }
127
129 eventQueue.clear();
130 }
131
133 const utils::Timeval& currentTime,
134 const sigset_t& sigMask,
135 int& activeDescriptorCount) {
136 TickStatus tickStatus = TickStatus::SUCCESS;
137
138 if (observedEventReceiverCount() > 0 || !timerEventPublisher->empty() || !eventQueue.empty()) {
139 utils::Timeval nextTimeout = std::min(getNextTimeout(currentTime), tickTimeOut);
140
141 activeDescriptorCount = monitorDescriptors(nextTimeout, sigMask);
142
143 if (activeDescriptorCount < 0) {
144 if (errno == EINTR) {
145 tickStatus = TickStatus::INTERRUPTED;
146 } else {
147 tickStatus = TickStatus::TRACE;
148 }
149 }
150 } else {
151 tickStatus = TickStatus::NOOBSERVER;
152 }
153
154 return tickStatus;
155 }
156
157 void EventMultiplexer::spanActiveEvents(const utils::Timeval& currentTime, int activeDescriptorCount) {
159 spanActiveEvents(activeDescriptorCount);
160 }
161
162 void EventMultiplexer::executeEventQueue(const utils::Timeval& currentTime) {
163 eventQueue.execute(currentTime);
164 }
165
166 void EventMultiplexer::checkTimedOutEvents(const utils::Timeval& currentTime) {
167 for (DescriptorEventPublisher* const descriptorEventPublisher : descriptorEventPublishers) {
168 descriptorEventPublisher->checkTimedOutEvents(currentTime);
169 }
170 }
171
172 void EventMultiplexer::releaseExpiredResources(const utils::Timeval& currentTime) {
173 for (DescriptorEventPublisher* const descriptorEventPublisher : descriptorEventPublishers) {
174 descriptorEventPublisher->releaseDisabledEvents(currentTime);
175 }
178 }
179
180 utils::Timeval EventMultiplexer::getNextTimeout(const utils::Timeval& currentTime) {
182
183 if (eventQueue.empty()) {
184 for (const DescriptorEventPublisher* const descriptorEventPublisher : descriptorEventPublishers) {
185 nextTimeout = std::min(descriptorEventPublisher->getNextTimeout(currentTime), nextTimeout);
186 }
187 nextTimeout = std::min(timerEventPublisher->getNextTimeout(currentTime), nextTimeout);
188 nextTimeout = std::max(nextTimeout, utils::Timeval()); // In case nextTimeout is negative
189 } else {
190 nextTimeout = 0;
191 }
192
193 return nextTimeout;
194 }
195
197 return std::accumulate(descriptorEventPublishers.begin(),
198 descriptorEventPublishers.end(),
199 0,
200 [](int count, const DescriptorEventPublisher* descriptorEventPublisher) -> int {
201 return count + descriptorEventPublisher->getObservedEventReceiverCount();
202 });
203 }
204
206 return std::accumulate(descriptorEventPublishers.begin(),
207 descriptorEventPublishers.end(),
208 -1,
209 [](int count, const DescriptorEventPublisher* descriptorEventPublisher) -> int {
210 return std::max(descriptorEventPublisher->maxFd(), count);
211 });
212 }
213
218
220 delete executeQueue;
221 delete publishQueue;
222 }
223
225 publishQueue->push_back(event); // do not allow two or more same events in one tick
226 }
227
229 publishQueue->remove(event); // in case of erase remove the event from the published queue
230 }
231
232 void EventMultiplexer::EventQueue::execute(const utils::Timeval& currentTime) {
233 std::swap(executeQueue, publishQueue);
234
235 for (Event* event : *executeQueue) {
236 event->dispatch(currentTime);
237 }
238
239 executeQueue->clear();
240 }
241
243 return publishQueue->empty();
244 }
245
247 std::swap(executeQueue, publishQueue);
248
249 for (const Event* event : *executeQueue) {
250 event->getEventReceiver()->destruct();
251 }
252
253 executeQueue->clear();
254 }
255
256} // namespace core
static void execDlCloseDeleyed()
void execute(const utils::Timeval &currentTime)
virtual int monitorDescriptors(utils::Timeval &tickTimeOut, const sigset_t &sigMask)=0
void releaseExpiredResources(const utils::Timeval &currentTime)
utils::Timeval getNextTimeout(const utils::Timeval &currentTime)
void checkTimedOutEvents(const utils::Timeval &currentTime)
TickStatus waitForEvents(const utils::Timeval &tickTimeOut, const utils::Timeval &currentTime, const sigset_t &sigMask, int &activeDescriptorCount)
TimerEventPublisher & getTimerEventPublisher()
TickStatus tick(const utils::Timeval &tickTimeOut, const sigset_t &sigMask)
void spanActiveEvents(const utils::Timeval &currentTime, int activeDescriptorCount)
void span(core::Event *event)
virtual void spanActiveEvents(int activeDescriptorCount)=0
DescriptorEventPublisher & getDescriptorEventPublisher(DISP_TYPE dispType)
void relax(core::Event *event)
EventMultiplexer(DescriptorEventPublisher *readDescriptorEventPublisher, DescriptorEventPublisher *writeDescriptorEventPublisher, DescriptorEventPublisher *exceptionDescriptorEventPublisher)
void executeEventQueue(const utils::Timeval &currentTime)
core::TimerEventPublisher *const timerEventPublisher
utils::Timeval getNextTimeout(const utils::Timeval &currentTime)
void spanActiveEvents(const utils::Timeval &currentTime)
static Timeval currentTime()
Definition Timeval.cpp:76
Timeval() noexcept
Definition Timeval.cpp:55
Timeval & operator=(const Timeval &timeVal)
Definition Timeval.cpp:83
Definition SNodeC.h:57
TickStatus
Definition TickStatus.h:51