w11 - cpp 0.794
Backend server for Rlink and w11
Loading...
Searching...
No Matches
ReventLoop.cpp
Go to the documentation of this file.
1// $Id: ReventLoop.cpp 1186 2019-07-12 17:49:59Z mueller $
2// SPDX-License-Identifier: GPL-3.0-or-later
3// Copyright 2013-2019 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
4//
5// Revision History:
6// Date Rev Version Comment
7// 2019-05-17 1150 1.3 BUGFIX: don't call handler when fUpdatePoll true
8// 2018-12-19 1090 1.2.6 use RosPrintf(bool)
9// 2018-12-18 1089 1.2.5 use c++ style casts
10// 2018-12-17 1085 1.2.4 use std::lock_guard instead of boost
11// 2018-12-15 1083 1.2.3 AddPollHandler(): use rval ref and move
12// 2018-11-09 1066 1.2.2 use emplace_back
13// 2017-04-07 868 1.2.1 Dump(): add detail arg
14// 2015-04-04 662 1.2 BUGFIX: fix race in Stop(), add UnStop,StopPending
15// 2013-04-27 511 1.1.3 BUGFIX: logic in DoCall() fixed (loop range)
16// 2013-03-05 495 1.1.2 add exception catcher to EventLoop
17// 2013-03-01 493 1.1.1 DoCall(): remove handler on negative return
18// 2013-02-22 491 1.1 use new RlogFile/RlogMsg interfaces
19// 2013-01-11 473 1.0 Initial version
20// ---------------------------------------------------------------------------
21
26#include <string.h>
27#include <poll.h>
28#include <errno.h>
29
30#include <mutex>
31
34#include "librtools/RosFill.hpp"
35#include "librtools/RlogMsg.hpp"
36
37#include "ReventLoop.hpp"
38
39using namespace std;
40
46// all method definitions in namespace Retro
47namespace Retro {
48
49//------------------------------------------+-----------------------------------
51
53 : fStopPending(false),
54 fUpdatePoll(false),
55 fPollDscMutex(),
56 fPollDsc(),
57 fPollFd(),
58 fPollHdl(),
59 fTraceLevel(0),
60 fspLog()
61{}
62
63//------------------------------------------+-----------------------------------
65
67{}
68
69//------------------------------------------+-----------------------------------
71
72// by default handlers should start with:
73// if (pfd.revents & (~pfd.events)) return -1;
74
75void ReventLoop::AddPollHandler(pollhdl_t&& pollhdl, int fd, short events)
76{
77 lock_guard<mutex> lock(fPollDscMutex);
78
79 for (size_t i=0; i<fPollDsc.size(); i++) {
80 if (fPollDsc[i].fFd == fd &&
81 fPollDsc[i].fEvents == events) {
82 throw Rexception("ReventLoop::AddPollHandler()",
83 "Bad args: duplicate handler");
84 }
85 }
86
87 fPollDsc.emplace_back(move(pollhdl),fd,events);
88 fUpdatePoll = true;
89
90 if (fspLog && fTraceLevel >= 1) {
91 RlogMsg lmsg(*fspLog, 'I');
92 lmsg << "eloop: add handler: " << fd << "," << RosPrintf(events,"x");
93 }
94
95 return;
96}
97
98//------------------------------------------+-----------------------------------
100
101void ReventLoop::RemovePollHandler(int fd, short events, bool nothrow)
102{
103 lock_guard<mutex> lock(fPollDscMutex);
104
105 for (size_t i=0; i<fPollDsc.size(); i++) {
106 if (fPollDsc[i].fFd == fd &&
107 fPollDsc[i].fEvents == events) {
108 fPollDsc.erase(fPollDsc.begin()+i);
109 fUpdatePoll = true;
110 if (fspLog && fTraceLevel >= 1) {
111 RlogMsg lmsg(*fspLog, 'I');
112 lmsg << "eloop: remove handler: " << fd << "," << RosPrintf(events,"x");
113 }
114 return;
115 }
116 }
117 if (!nothrow) throw Rexception("ReventLoop::RemovePollHandler()",
118 "Bad args: unknown handler");
119}
120
121//------------------------------------------+-----------------------------------
123
124bool ReventLoop::TestPollHandler(int fd, short events)
125{
126 lock_guard<mutex> lock(fPollDscMutex);
127
128 for (size_t i=0; i<fPollDsc.size(); i++) {
129 if (fPollDsc[i].fFd == fd &&
130 fPollDsc[i].fEvents == events) {
131 return true;
132 }
133 }
134 return false;
135}
136
137//------------------------------------------+-----------------------------------
139
141{
142 lock_guard<mutex> lock(fPollDscMutex);
143
144 for (size_t i=0; i<fPollDsc.size(); i++) {
145 if (fPollDsc[i].fFd == fd) {
146 fPollDsc.erase(fPollDsc.begin()+i);
147 fUpdatePoll = true;
148 i--; // re-probe this index
149 }
150 }
151 return;
152}
153
154//------------------------------------------+-----------------------------------
156
158{
159 fUpdatePoll = true;
160
161 try {
162 while (!StopPending()) {
163 int irc = DoPoll();
164 if (fPollFd.size() == 0) break;
165 if (irc>0) DoCall();
166 }
167 } catch (exception& e) {
168 if (fspLog) {
169 RlogMsg lmsg(*fspLog, 'F');
170 lmsg << "eloop: crashed with exception: " << e.what();
171 }
172 return;
173 }
174
175 return;
176}
177
178//------------------------------------------+-----------------------------------
180
181void ReventLoop::Dump(std::ostream& os, int ind, const char* text,
182 int /*detail*/) const
183{
184 RosFill bl(ind);
185 os << bl << (text?text:"--") << "ReventLoop @ " << this << endl;
186 os << bl << " fStopPending: " << RosPrintf(fStopPending) << endl;
187 os << bl << " fUpdatePoll: " << RosPrintf(fUpdatePoll) << endl;
188 {
189 lock_guard<mutex> lock(const_cast<ReventLoop*>(this)->fPollDscMutex);
190 os << bl << " fPollDsc.size: " << fPollDsc.size() << endl;
191 os << bl << " fPollFd.size: " << fPollFd.size() << endl;
192 os << bl << " fPollHdl.size: " << fPollHdl.size() << endl;
193 for (size_t i=0; i<fPollDsc.size(); i++) {
194 os << bl << " [" << RosPrintf(i,"d",3) << "]:"
195 << " fd:" << RosPrintf(fPollDsc[i].fFd,"d",3)
196 << " evt:" << RosPrintf(fPollDsc[i].fEvents,"x",2)
197 << " hdl:" << bool(fPollDsc[i].fHandler)
198 << endl;
199 }
200 }
201 os << bl << " fTraveLevel: " << fTraceLevel << endl;
202 os << bl << " fspLog: " << fspLog.get() << endl;
203
204 return;
205}
206
207//------------------------------------------+-----------------------------------
209
210int ReventLoop::DoPoll(int timeout)
211{
212 int irc = 0;
213 do {
214 if (fUpdatePoll) {
215 lock_guard<mutex> lock(fPollDscMutex);
216
217 fPollFd.resize(fPollDsc.size());
218 fPollHdl.resize(fPollDsc.size());
219 for (size_t i=0; i<fPollDsc.size(); i++) {
220 fPollFd[i].fd = fPollDsc[i].fFd;
221 fPollFd[i].events = fPollDsc[i].fEvents;
222 fPollFd[i].revents = 0;
223 fPollHdl[i] = fPollDsc[i].fHandler;
224 }
225 fUpdatePoll = false;
226
227 if (fspLog && fTraceLevel >= 1) {
228 RlogMsg lmsg(*fspLog, 'I');
229 lmsg << "eloop: redo pollfd list, size=" << fPollDsc.size() << endl;
230 }
231 }
232
233 if (fPollFd.size() == 0) return 0;
234 irc = poll(fPollFd.data(), fPollFd.size(), timeout);
235 if (irc < 0 && errno == EINTR) return 0;
236 if (irc < 0)
237 throw Rexception("ReventLoop::EventLoop()", "poll() failed: ", errno);
238
239 if (fspLog && fTraceLevel >= 2) {
240 RlogMsg lmsg(*fspLog, 'I');
241 lmsg << "eloop: poll(): rc=" << irc;
242 for (size_t i=0; i<fPollFd.size(); i++) {
243 if (fPollFd[i].revents == 0) continue;
244 lmsg << " (" << fPollFd[i].fd
245 << "," << RosPrintf(fPollFd[i].events,"x")
246 << "," << RosPrintf(fPollFd[i].revents,"x") << ")";
247 }
248 }
249
250 // repeat poll in case fUpdatePoll is active
251 } while (fUpdatePoll);
252
253 return irc;
254}
255
256//------------------------------------------+-----------------------------------
258
260{
261 for (size_t i=0; i<fPollFd.size(); i++) {
262 if (fUpdatePoll) break;
263 if (fPollFd[i].revents) {
264 int irc = fPollHdl[i](fPollFd[i]);
265 // remove handler on negative return (nothrow=true to prevent remove race)
266 if (irc < 0) {
267 if (fspLog && fTraceLevel >= 1) {
268 RlogMsg lmsg(*fspLog, 'I');
269 lmsg << "eloop: handler(" << fPollFd[i].fd
270 << "," << RosPrintf(fPollFd[i].events,"x")
271 << ") got " << RosPrintf(fPollFd[i].revents,"x")
272 << " and requested removal";
273 }
274 RemovePollHandler(fPollFd[i].fd, fPollFd[i].events, true);
275 }
276 }
277 }
278 return;
279}
280
281} // end namespace Retro
FIXME_docs.
Definition: ReventLoop.hpp:39
virtual void EventLoop()
FIXME_docs.
Definition: ReventLoop.cpp:157
std::shared_ptr< RlogFile > fspLog
log file ptr
Definition: ReventLoop.hpp:89
virtual ~ReventLoop()
FIXME_docs.
Definition: ReventLoop.cpp:66
ReventLoop()
FIXME_docs.
Definition: ReventLoop.cpp:52
std::mutex fPollDscMutex
Definition: ReventLoop.hpp:84
virtual void Dump(std::ostream &os, int ind=0, const char *text=0, int detail=0) const
FIXME_docs.
Definition: ReventLoop.cpp:181
void DoCall(void)
FIXME_docs.
Definition: ReventLoop.cpp:259
std::vector< pollfd > fPollFd
Definition: ReventLoop.hpp:86
int DoPoll(int timeout=-1)
FIXME_docs.
Definition: ReventLoop.cpp:210
void AddPollHandler(pollhdl_t &&pollhdl, int fd, short events=POLLIN)
FIXME_docs.
Definition: ReventLoop.cpp:75
std::vector< PollDsc > fPollDsc
Definition: ReventLoop.hpp:85
bool StopPending()
FIXME_docs.
Definition: ReventLoop.ipp:42
uint32_t fTraceLevel
trace level
Definition: ReventLoop.hpp:88
std::function< int(const pollfd &)> pollhdl_t
Definition: ReventLoop.hpp:41
bool TestPollHandler(int fd, short events=POLLIN)
FIXME_docs.
Definition: ReventLoop.cpp:124
std::vector< pollhdl_t > fPollHdl
Definition: ReventLoop.hpp:87
void RemovePollHandler(int fd, short events, bool nothrow=false)
FIXME_docs.
Definition: ReventLoop.cpp:101
FIXME_docs.
Definition: Rexception.hpp:29
FIXME_docs.
Definition: RlogMsg.hpp:24
I/O appicator to generate fill characters.
Definition: RosFill.hpp:24
RosPrintfS< bool > RosPrintf(bool value, const char *form=0, int width=0, int prec=0)
Creates a print object for the formatted output of a bool value.
Definition: RosPrintf.ipp:38
Declaration of class ReventLoop.
Definition: ReventLoop.cpp:47