SNode.C
Loading...
Searching...
No Matches
EventLoop.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#include "core/EventLoop.h"
21
22#include "core/DynamicLoader.h"
23#include "core/EventMultiplexer.h"
24
25#ifndef DOXYGEN_SHOULD_SKIP_THIS
26
27#include "log/Logger.h"
28#include "utils/Config.h"
29#include "utils/Timeval.h"
30#include "utils/system/signal.h"
31
32#include <chrono>
33#include <cstring>
34
35#endif /* DOXYGEN_SHOULD_SKIP_THIS */
36
37namespace core {
38
39 int EventLoop::stopsig = 0;
40 unsigned long EventLoop::tickCounter = 0;
41 core::State EventLoop::eventLoopState = State::LOADED;
42
44 std::string tick = std::to_string(EventLoop::getTickCounter());
45
46 if (tick.length() < 13) {
47 tick.insert(0, 13 - tick.length(), '0');
48 }
49
50 return tick;
51 }
52
53 EventLoop::EventLoop()
54 : eventMultiplexer(::EventMultiplexer()) {
55 }
56
57 EventLoop& EventLoop::instance() {
58 static EventLoop eventLoop;
59
60 return eventLoop;
61 }
62
63 unsigned long EventLoop::getTickCounter() {
64 return tickCounter;
65 }
66
67 EventMultiplexer& EventLoop::getEventMultiplexer() {
68 return eventMultiplexer;
69 }
70
71 State EventLoop::getEventLoopState() {
72 return eventLoopState;
73 }
74
75 // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, hicpp-avoid-c-arrays, modernize-avoid-c-arrays)
76 bool EventLoop::init(int argc, char* argv[]) {
77 struct sigaction sact{};
78 sigemptyset(&sact.sa_mask);
79 sact.sa_flags = 0;
80 sact.sa_handler = SIG_IGN;
81
82 struct sigaction oldPipeAct{};
83 sigaction(SIGPIPE, &sact, &oldPipeAct);
84
85 struct sigaction oldIntAct{};
86 sigaction(SIGINT, &sact, &oldIntAct);
87
88 struct sigaction oldTermAct{};
89 sigaction(SIGTERM, &sact, &oldTermAct);
90
91 struct sigaction oldAlarmAct{};
92 sigaction(SIGALRM, &sact, &oldAlarmAct);
93
94 struct sigaction oldHupAct{};
95 sigaction(SIGHUP, &sact, &oldHupAct);
96
97 logger::Logger::setCustomFormatSpec("%tick", core::getTickCounterAsString);
98
99 if (utils::Config::init(argc, argv)) {
100 eventLoopState = State::INITIALIZED;
101
102 LOG(TRACE) << "SNode.C: Starting ... HELLO";
103 }
104
105 sigaction(SIGPIPE, &oldPipeAct, nullptr);
106 sigaction(SIGINT, &oldIntAct, nullptr);
107 sigaction(SIGTERM, &oldTermAct, nullptr);
108 sigaction(SIGALRM, &oldAlarmAct, nullptr);
109 sigaction(SIGHUP, &oldHupAct, nullptr);
110
111 return eventLoopState == State::INITIALIZED;
112 }
113
114 TickStatus EventLoop::_tick(const utils::Timeval& tickTimeOut) {
115 TickStatus tickStatus = TickStatus::SUCCESS;
116
117 tickCounter++;
118
119 sigset_t newSet{};
120 sigaddset(&newSet, SIGINT);
121 sigaddset(&newSet, SIGTERM);
122 sigaddset(&newSet, SIGALRM);
123 sigaddset(&newSet, SIGHUP);
124
125 sigset_t oldSet{};
126 sigprocmask(SIG_BLOCK, &newSet, &oldSet);
127
128 if (eventLoopState == State::RUNNING || eventLoopState == State::STOPPING) {
129 tickStatus = eventMultiplexer.tick(tickTimeOut, oldSet);
130 }
131
132 sigprocmask(SIG_SETMASK, &oldSet, nullptr);
133
134 return tickStatus;
135 }
136
137 TickStatus EventLoop::tick(const utils::Timeval& timeOut) {
138 TickStatus tickStatus = TickStatus::TRACE;
139
140 if (eventLoopState == State::INITIALIZED) {
141 struct sigaction sact{};
142 sigemptyset(&sact.sa_mask);
143 sact.sa_flags = 0;
144 sact.sa_handler = SIG_IGN;
145
146 struct sigaction oldPipeAct{};
147 sigaction(SIGPIPE, &sact, &oldPipeAct);
148
149 tickStatus = EventLoop::instance()._tick(timeOut);
150
151 sigaction(SIGPIPE, &oldPipeAct, nullptr);
152 } else {
153 EventLoop::instance().eventMultiplexer.clearEventQueue();
154 free();
155
156 PLOG(FATAL) << "Core: not initialized: No events will be processed\nCall SNodeC::init(argc, argv) before SNodeC::tick().";
157 }
158
159 return tickStatus;
160 }
161
162 int EventLoop::start(const utils::Timeval& timeOut) {
163 struct sigaction sact{};
164 sigemptyset(&sact.sa_mask);
165 sact.sa_flags = 0;
166 sact.sa_handler = SIG_IGN;
167
168 struct sigaction oldPipeAct{};
169 sigaction(SIGPIPE, &sact, &oldPipeAct);
170
171 sact.sa_handler = EventLoop::stoponsig;
172
173 struct sigaction oldIntAct{};
174 sigaction(SIGINT, &sact, &oldIntAct);
175
176 struct sigaction oldTermAct{};
177 sigaction(SIGTERM, &sact, &oldTermAct);
178
179 struct sigaction oldAlarmAct{};
180 sigaction(SIGALRM, &sact, &oldAlarmAct);
181
182 struct sigaction oldHupAct{};
183 sigaction(SIGHUP, &sact, &oldHupAct);
184
185 if (eventLoopState == State::INITIALIZED && utils::Config::bootstrap()) {
186 eventLoopState = State::RUNNING;
187 core::TickStatus tickStatus = TickStatus::SUCCESS;
188
189 LOG(TRACE) << "Core::EventLoop: started";
190
191 do {
192 tickStatus = EventLoop::instance()._tick(timeOut);
193 } while ((tickStatus == TickStatus::SUCCESS || tickStatus == TickStatus::INTERRUPTED) && eventLoopState == State::RUNNING);
194
195 switch (tickStatus) {
196 case TickStatus::SUCCESS:
197 LOG(TRACE) << "Core::EventLoop: Stopped";
198 break;
199 case TickStatus::NOOBSERVER:
200 LOG(TRACE) << "Core::EventLoop: No Observer";
201 break;
202 case TickStatus::INTERRUPTED:
203 LOG(TRACE) << "Core::EventLoop: Interrupted";
204 break;
205 case TickStatus::TRACE:
206 PLOG(FATAL) << "Core::EventLoop: _tick()";
207 break;
208 }
209 }
210
211 sigaction(SIGPIPE, &oldPipeAct, nullptr);
212 sigaction(SIGTERM, &oldTermAct, nullptr);
213 sigaction(SIGALRM, &oldAlarmAct, nullptr);
214 sigaction(SIGHUP, &oldHupAct, nullptr);
215
216 free();
217
218 sigaction(SIGINT, &oldIntAct, nullptr);
219
220 return stopsig;
221 }
222
223 void EventLoop::stop() {
224 eventLoopState = State::STOPPING;
225 }
226
227 void EventLoop::free() {
228 std::string signal = "SIG" + utils::system::sigabbrev_np(stopsig);
229
230 if (signal == "SIGUNKNOWN") {
231 signal = std::to_string(stopsig);
232 }
233
234 if (stopsig != 0) {
235 LOG(TRACE) << "Core: Sending signal " << signal << " to all DescriptorEventReceivers";
236
237 EventLoop::instance().eventMultiplexer.signal(stopsig);
238 }
239
240 eventLoopState = State::STOPPING;
241
242 utils::Timeval timeout = 2;
243
244 core::TickStatus tickStatus = TickStatus::SUCCESS;
245 do {
246 auto t1 = std::chrono::system_clock::now();
247 const utils::Timeval timeoutOp = timeout;
248
249 tickStatus = EventLoop::instance()._tick(timeoutOp);
250
251 auto t2 = std::chrono::system_clock::now();
252 const std::chrono::duration<double> seconds = t2 - t1;
253
254 timeout -= seconds.count();
255 } while (timeout > 0 && (tickStatus == TickStatus::SUCCESS));
256
257 LOG(TRACE) << "Core: Terminate all stalled DescriptorEventReceivers";
258
259 EventLoop::instance().eventMultiplexer.terminate();
260
261 LOG(TRACE) << "Core: Close all libraries opened during runtime";
262
263 DynamicLoader::execDlCloseAll();
264
265 LOG(TRACE) << "Core:: Clean up the filesystem";
266
267 utils::Config::terminate();
268
269 LOG(TRACE) << "Core:: All resources released";
270
271 LOG(TRACE) << "SNode.C: Ended ... BYE";
272 }
273
274 void EventLoop::stoponsig(int sig) {
275 LOG(TRACE) << "Core: Received signal '" << strsignal(sig) << "' (SIG" << utils::system::sigabbrev_np(sig) << " = " << sig << ")";
276 stopsig = sig;
277 stop();
278 }
279
280} // namespace core
static std::string getTickCounterAsString(const el::LogMessage *logMessage)
Definition EventLoop.cpp:43