• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

igor-krechetov / hsmcpp / 4509400661

pending completion
4509400661

push

github

igor-krechetov
[0.33.0][r] improvement to timers API

46 of 46 new or added lines in 5 files covered. (100.0%)

1921 of 2338 relevant lines covered (82.16%)

161238.04 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.95
/src/HsmEventDispatcherBase.cpp
1
// Copyright (C) 2021 Igor Krechetov
2
// Distributed under MIT license. See file LICENSE for details
3

4
#include "hsmcpp/HsmEventDispatcherBase.hpp"
5

6
#include "hsmcpp/logging.hpp"
7
#include "hsmcpp/os/CriticalSection.hpp"
8
#include "hsmcpp/os/LockGuard.hpp"
9

10
namespace hsmcpp {
11

12
#undef HSM_TRACE_CLASS
13
#define HSM_TRACE_CLASS "HsmEventDispatcherBase"
14

15
HsmEventDispatcherBase::HsmEventDispatcherBase(const size_t eventsCacheSize) {
160✔
16
    mEnqueuedEvents.reserve(eventsCacheSize);
160✔
17
}
160✔
18

19
HsmEventDispatcherBase::~HsmEventDispatcherBase() {}
462✔
20

21
void HsmEventDispatcherBase::handleDelete(HsmEventDispatcherBase* dispatcher) {
160✔
22
    if (nullptr != dispatcher) {
160✔
23
        dispatcher->stop();
160✔
24

25
        if (true == dispatcher->deleteSafe()) {
160✔
26
            delete dispatcher;
64✔
27
        }
28
    }
29
}
160✔
30

31
void HsmEventDispatcherBase::stop() {
399✔
32
    HSM_TRACE_CALL_DEBUG();
399✔
33
    mStopDispatcher = true;
399✔
34
    // NOTE: child classes must provide additional logic
35
}
399✔
36

37
HandlerID_t HsmEventDispatcherBase::registerEventHandler(const EventHandlerFunc_t& handler) {
2,120✔
38
    HSM_TRACE_CALL_DEBUG();
2,120✔
39
    HandlerID_t id = getNextHandlerID();
2,120✔
40
    LockGuard lck(mHandlersSync);
2,120✔
41

42
    mEventHandlers.emplace(id, handler);
2,120✔
43

44
    return id;
2,120✔
45
}
2,120✔
46

47
void HsmEventDispatcherBase::unregisterEventHandler(const HandlerID_t handlerID) {
1,990✔
48
    HSM_TRACE_CALL_DEBUG_ARGS("handlerID=%d", handlerID);
1,990✔
49
    LockGuard lck(mHandlersSync);
1,990✔
50

51
    mEventHandlers.erase(handlerID);
1,990✔
52
}
1,990✔
53

54
void HsmEventDispatcherBase::emitEvent(const HandlerID_t handlerID) {
1,668,438✔
55
    HSM_TRACE_CALL_DEBUG();
1,668,438✔
56

57
    {
1,668,438✔
58
        LockGuard lck(mEmitSync);
1,668,438✔
59
        mPendingEvents.push_back(handlerID);
1,683,751✔
60
    }
1,683,751✔
61

62
    notifyDispatcherAboutEvent();
1,682,852✔
63

64
    // NOTE: this is not a full implementation. child classes must implement additional logic
65
}
1,682,417✔
66

67
bool HsmEventDispatcherBase::enqueueEvent(const HandlerID_t handlerID, const EventID_t event) {
10✔
68
    bool wasAdded = false;
10✔
69

70
    if (mEnqueuedEvents.size() < mEnqueuedEvents.capacity()) {
10✔
71
        EnqueuedEventInfo newEvent;
10✔
72

73
        newEvent.handlerID = handlerID;
10✔
74
        newEvent.eventID = event;
10✔
75

76
        {
10✔
77
            CriticalSection cs(mEnqueuedEventsSync);
10✔
78
            mEnqueuedEvents.push_back(newEvent);
10✔
79
        }
10✔
80

81
        wasAdded = true;
10✔
82
        notifyDispatcherAboutEvent();
10✔
83
    }
84

85
    return wasAdded;
10✔
86
}
87

88
HandlerID_t HsmEventDispatcherBase::registerEnqueuedEventHandler(const EnqueuedEventHandlerFunc_t& handler) {
2,000✔
89
    HSM_TRACE_CALL_DEBUG();
2,000✔
90
    HandlerID_t id = getNextHandlerID();
2,000✔
91
    LockGuard lck(mHandlersSync);
2,000✔
92

93
    mEnqueuedEventHandlers.emplace(id, handler);
2,000✔
94

95
    return id;
2,000✔
96
}
2,000✔
97

98
void HsmEventDispatcherBase::unregisterEnqueuedEventHandler(const HandlerID_t handlerID) {
1,990✔
99
    HSM_TRACE_CALL_DEBUG_ARGS("handlerID=%d", handlerID);
1,990✔
100
    LockGuard lck(mHandlersSync);
1,990✔
101

102
    mEnqueuedEventHandlers.erase(handlerID);
1,990✔
103
}
1,990✔
104

105
HandlerID_t HsmEventDispatcherBase::registerTimerHandler(const TimerHandlerFunc_t& handler) {
2,000✔
106
    const HandlerID_t newID = getNextHandlerID();
2,000✔
107
    LockGuard lck(mHandlersSync);
2,000✔
108

109
    mTimerHandlers.emplace(newID, handler);
2,000✔
110

111
    return newID;
2,000✔
112
}
2,000✔
113

114
void HsmEventDispatcherBase::unregisterTimerHandler(const HandlerID_t handlerID) {
1,990✔
115
    LockGuard lck(mHandlersSync);
1,990✔
116
    auto itHandler = mTimerHandlers.find(handlerID);
1,990✔
117

118
    if (mTimerHandlers.end() != itHandler) {
1,990✔
119
        for (auto itTimer = mActiveTimers.begin(); itTimer != mActiveTimers.end();) {
1,990✔
120
            if (handlerID == itTimer->second.handlerID) {
110✔
121
                stopTimerImpl(itTimer->first);
110✔
122
                itTimer = mActiveTimers.erase(itTimer);
110✔
123
            } else {
124
                ++itTimer;
2,100✔
125
            }
126
        }
127

128
        mTimerHandlers.erase(itHandler);
1,990✔
129
    }
130
}
1,990✔
131

132
void HsmEventDispatcherBase::startTimer(const HandlerID_t handlerID,
150✔
133
                                        const TimerID_t timerID,
134
                                        const unsigned int intervalMs,
135
                                        const bool isSingleShot) {
136
    HSM_TRACE_CALL_DEBUG_ARGS("handlerID=%d, timerID=%d, intervalMs=%d, isSingleShot=%d",
137
                              handlerID,
138
                              timerID,
139
                              intervalMs,
140
                              BOOL2INT(isSingleShot));
150✔
141
    LockGuard lck(mHandlersSync);
150✔
142

143
    if (mTimerHandlers.find(handlerID) != mTimerHandlers.end()) {
300✔
144
        auto it = mActiveTimers.find(timerID);
150✔
145

146
        if (mActiveTimers.end() != it) {
150✔
147
            it->second.handlerID = handlerID;
10✔
148
            it->second.intervalMs = intervalMs;
10✔
149
            it->second.isSingleShot = isSingleShot;
10✔
150

151
            // restart timer
152
            stopTimerImpl(timerID);
10✔
153
            startTimerImpl(timerID, it->second.intervalMs, it->second.isSingleShot);
10✔
154
        } else {
155
            TimerInfo newTimer;
140✔
156

157
            newTimer.handlerID = handlerID;
140✔
158
            newTimer.intervalMs = intervalMs;
140✔
159
            newTimer.isSingleShot = isSingleShot;
140✔
160

161
            mActiveTimers.emplace(timerID, newTimer);
140✔
162
            startTimerImpl(timerID, intervalMs, isSingleShot);
140✔
163
        }
164
    }
165
}
150✔
166

167
void HsmEventDispatcherBase::restartTimer(const TimerID_t timerID) {
20✔
168
    HSM_TRACE_CALL_DEBUG_ARGS("timerID=%d", SC2INT(timerID));
20✔
169
    LockGuard lck(mHandlersSync);
20✔
170
    auto it = mActiveTimers.find(timerID);
20✔
171

172
    if (mActiveTimers.end() != it) {
20✔
173
        stopTimerImpl(timerID);
20✔
174
        startTimerImpl(timerID, it->second.intervalMs, it->second.isSingleShot);
20✔
175
    }
176
}
20✔
177

178
void HsmEventDispatcherBase::stopTimer(const TimerID_t timerID) {
30✔
179
    HSM_TRACE_CALL_DEBUG_ARGS("timerID=%d", SC2INT(timerID));
30✔
180
    LockGuard lck(mHandlersSync);
30✔
181
    auto it = mActiveTimers.find(timerID);
30✔
182

183
    HSM_TRACE_DEBUG("mActiveTimers=%lu", mActiveTimers.size());
30✔
184

185
    if (mActiveTimers.end() != it) {
30✔
186
        stopTimerImpl(timerID);
30✔
187
        mActiveTimers.erase(it);
30✔
188
    }
189
}
30✔
190

191
bool HsmEventDispatcherBase::isTimerRunning(const TimerID_t timerID) {
30✔
192
    return (mActiveTimers.find(timerID) != mActiveTimers.end());
30✔
193
}
194

195
int HsmEventDispatcherBase::getNextHandlerID() {
6,120✔
196
    return mNextHandlerId++;
6,120✔
197
}
198

199
void HsmEventDispatcherBase::unregisterAllEventHandlers() {
399✔
200
    LockGuard lck(mHandlersSync);
399✔
201
    mEventHandlers.clear();
399✔
202
}
399✔
203

204
EnqueuedEventHandlerFunc_t HsmEventDispatcherBase::getEnqueuedEventHandlerFunc(const HandlerID_t handlerID) const {
10✔
205
    // cppcheck-suppress misra-c2012-17.7 ; false-positive. This a function pointer, not function call.
206
    EnqueuedEventHandlerFunc_t func;
10✔
207
    auto it = mEnqueuedEventHandlers.find(handlerID);
10✔
208

209
    if (mEnqueuedEventHandlers.end() != it) {
10✔
210
        func = it->second;
10✔
211
    }
212

213
    return func;
10✔
214
}
×
215

216
HsmEventDispatcherBase::TimerInfo HsmEventDispatcherBase::getTimerInfo(const TimerID_t timerID) const {
130✔
217
    TimerInfo result;
130✔
218
    auto it = mActiveTimers.find(timerID);
130✔
219

220
    if (mActiveTimers.end() != it) {
130✔
221
        result = it->second;
130✔
222
    }
223

224
    return result;
130✔
225
}
226

227
TimerHandlerFunc_t HsmEventDispatcherBase::getTimerHandlerFunc(const HandlerID_t handlerID) const {
130✔
228
    // cppcheck-suppress misra-c2012-17.7 ; false-positive. This a function pointer, not function call.
229
    TimerHandlerFunc_t func;
130✔
230
    auto it = mTimerHandlers.find(handlerID);
130✔
231

232
    if (mTimerHandlers.end() != it) {
130✔
233
        func = it->second;
130✔
234
    }
235

236
    return func;
130✔
237
}
×
238

239
void HsmEventDispatcherBase::startTimerImpl(const TimerID_t timerID, const unsigned int intervalMs, const bool isSingleShot) {
×
240
    // do nothing. must be implemented in platfrom specific dispatcher
241
}
×
242

243
void HsmEventDispatcherBase::stopTimerImpl(const TimerID_t timerID) {
×
244
    // do nothing. must be implemented in platfrom specific dispatcher
245
}
×
246

247
bool HsmEventDispatcherBase::handleTimerEvent(const TimerID_t timerID) {
130✔
248
    HSM_TRACE_CALL_DEBUG_ARGS("timerID=%d", SC2INT(timerID));
130✔
249
    bool restartTimer = false;
130✔
250

251
    if (INVALID_HSM_TIMER_ID != timerID) {
130✔
252
        // NOTE: should lock the whole block to prevent situation when timer handler is unregistered during handler execution
253
        LockGuard lck(mHandlersSync);
130✔
254
        TimerInfo curTimer = getTimerInfo(timerID);
130✔
255

256
        HSM_TRACE_DEBUG("curTimer.handlerID=%d", curTimer.handlerID);
130✔
257

258
        if (INVALID_HSM_DISPATCHER_HANDLER_ID != curTimer.handlerID) {
130✔
259
            TimerHandlerFunc_t timerHandler = getTimerHandlerFunc(curTimer.handlerID);
130✔
260

261
            timerHandler(timerID);
130✔
262

263
            restartTimer = ((true == curTimer.isSingleShot) ? false : true);
130✔
264
        }
130✔
265
    }
130✔
266

267
    return restartTimer;
130✔
268
}
269

270
void HsmEventDispatcherBase::dispatchEnqueuedEvents() {
1,203,740✔
271
    if ((false == mStopDispatcher) && (false == mEnqueuedEvents.empty())) {
1,203,740✔
272
        HandlerID_t prevHandlerID = INVALID_HSM_DISPATCHER_HANDLER_ID;
10✔
273
        EnqueuedEventHandlerFunc_t callback;
10✔
274
        std::vector<EnqueuedEventInfo> currentEvents;
10✔
275

276
        {
10✔
277
            CriticalSection lck(mEnqueuedEventsSync);
10✔
278

279
            // copy instead of move. we want to keep memory allocated in mEnqueuedEvents
280
            currentEvents = mEnqueuedEvents;
10✔
281
            mEnqueuedEvents.clear();
10✔
282
        }
10✔
283

284
        // need to traverse events in reverse order
285
        for (auto it = currentEvents.rbegin(); (it != currentEvents.rend()) && (false == mStopDispatcher) ; ++it) {
20✔
286
            if (prevHandlerID != it->handlerID) {
10✔
287
                callback = getEnqueuedEventHandlerFunc(it->handlerID);
10✔
288
                prevHandlerID = it->handlerID;
10✔
289
            }
290

291
            callback(it->eventID);
20✔
292
        }
293
    }
20✔
294
}
1,203,740✔
295

296
void HsmEventDispatcherBase::dispatchPendingEvents() {
1,203,740✔
297
    std::list<HandlerID_t> events;
1,203,740✔
298

299
    {
1,203,740✔
300
        LockGuard lck(mEmitSync);
1,203,740✔
301
        events = std::move(mPendingEvents);
1,203,740✔
302
    }
1,203,740✔
303

304
    dispatchPendingEventsImpl(events);
1,203,740✔
305
}
1,203,740✔
306

307
void HsmEventDispatcherBase::dispatchPendingEventsImpl(const std::list<HandlerID_t>& events) {
1,203,740✔
308
    dispatchEnqueuedEvents();
1,203,740✔
309

310
    if ((false == mStopDispatcher) && (false == events.empty())) {
1,203,740✔
311
        std::map<HandlerID_t, EventHandlerFunc_t> eventHandlersCopy;
8,555✔
312

313
        {
8,555✔
314
            // TODO: workaround to prevent recursive lock if registerEventHandler/unregisterEventHandler is called from handler
315
            // callback
316
            LockGuard lck(mHandlersSync);
8,555✔
317
            eventHandlersCopy = mEventHandlers;
8,555✔
318
        }
8,555✔
319

320
        for (auto it = events.begin(); (it != events.end()) && (false == mStopDispatcher); ++it) {
1,692,101✔
321
            auto itHandler = eventHandlersCopy.find(*it);
1,683,546✔
322

323
            if (itHandler != eventHandlersCopy.end()) {
1,683,546✔
324
                // NOTE: if callback returns FALSE it means the handler doesn't want to process more events
325
                if (false == itHandler->second()) {
2,569,980✔
326
                    eventHandlersCopy.erase(itHandler);
384✔
327
                }
328
            }
329
        }
330
    }
8,555✔
331
}
1,203,740✔
332

333
}  // namespace hsmcpp
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc