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

igor-krechetov / hsmcpp / 4815527644

pending completion
4815527644

push

github

igor-krechetov
[0.35.0][r] Variant refactoring and custom types support (BREAKS INTERFACE)

329 of 329 new or added lines in 2 files covered. (100.0%)

3586 of 7885 relevant lines covered (45.48%)

49379.18 hits per line

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

97.04
/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,180✔
38
    HSM_TRACE_CALL_DEBUG();
2,180✔
39
    HandlerID_t id = getNextHandlerID();
2,180✔
40
    LockGuard lck(mHandlersSync);
2,180✔
41

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

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

47
void HsmEventDispatcherBase::unregisterEventHandler(const HandlerID_t handlerID) {
2,050✔
48
    HSM_TRACE_CALL_DEBUG_ARGS("handlerID=%d", handlerID);
2,050✔
49

50
    {
2,050✔
51
        LockGuard lck(mEmitSync);
2,050✔
52
        mPendingEvents.remove(handlerID);
2,050✔
53
    }
2,050✔
54
    {
2,050✔
55
        LockGuard lck(mHandlersSync);
2,050✔
56
        mEventHandlers.erase(handlerID);
2,050✔
57
    }
2,050✔
58
}
2,050✔
59

60
void HsmEventDispatcherBase::emitEvent(const HandlerID_t handlerID) {
1,679,794✔
61
    HSM_TRACE_CALL_DEBUG();
1,679,794✔
62

63
    {
1,679,794✔
64
        LockGuard lck(mEmitSync);
1,679,794✔
65
        mPendingEvents.push_back(handlerID);
1,690,014✔
66
    }
1,690,014✔
67

68
    notifyDispatcherAboutEvent();
1,689,647✔
69

70
    // NOTE: this is not a full implementation. child classes must implement additional logic
71
}
1,689,486✔
72

73
bool HsmEventDispatcherBase::enqueueEvent(const HandlerID_t handlerID, const EventID_t event) {
10✔
74
    bool wasAdded = false;
10✔
75

76
    if (mEnqueuedEvents.size() < mEnqueuedEvents.capacity()) {
10✔
77
        EnqueuedEventInfo newEvent;
10✔
78

79
        newEvent.handlerID = handlerID;
10✔
80
        newEvent.eventID = event;
10✔
81

82
        {
10✔
83
            CriticalSection cs(mEnqueuedEventsSync);
10✔
84
            mEnqueuedEvents.push_back(newEvent);
10✔
85
        }
10✔
86

87
        wasAdded = true;
10✔
88
        notifyDispatcherAboutEvent();
10✔
89
    }
90

91
    return wasAdded;
10✔
92
}
93

94
HandlerID_t HsmEventDispatcherBase::registerEnqueuedEventHandler(const EnqueuedEventHandlerFunc_t& handler) {
2,060✔
95
    HSM_TRACE_CALL_DEBUG();
2,060✔
96
    HandlerID_t id = getNextHandlerID();
2,060✔
97
    LockGuard lck(mHandlersSync);
2,060✔
98

99
    mEnqueuedEventHandlers.emplace(id, handler);
2,060✔
100

101
    return id;
2,060✔
102
}
2,060✔
103

104
void HsmEventDispatcherBase::unregisterEnqueuedEventHandler(const HandlerID_t handlerID) {
2,050✔
105
    HSM_TRACE_CALL_DEBUG_ARGS("handlerID=%d", handlerID);
2,050✔
106
    LockGuard lck(mHandlersSync);
2,050✔
107

108
    mEnqueuedEventHandlers.erase(handlerID);
2,050✔
109
}
2,050✔
110

111
HandlerID_t HsmEventDispatcherBase::registerTimerHandler(const TimerHandlerFunc_t& handler) {
2,060✔
112
    const HandlerID_t newID = getNextHandlerID();
2,060✔
113
    LockGuard lck(mHandlersSync);
2,060✔
114

115
    mTimerHandlers.emplace(newID, handler);
2,060✔
116

117
    return newID;
2,060✔
118
}
2,060✔
119

120
void HsmEventDispatcherBase::unregisterTimerHandler(const HandlerID_t handlerID) {
2,050✔
121
    LockGuard lck(mHandlersSync);
2,050✔
122
    auto itHandler = mTimerHandlers.find(handlerID);
2,050✔
123

124
    if (mTimerHandlers.end() != itHandler) {
2,050✔
125
        for (auto itTimer = mActiveTimers.begin(); itTimer != mActiveTimers.end();) {
2,050✔
126
            if (handlerID == itTimer->second.handlerID) {
110✔
127
                stopTimerImpl(itTimer->first);
110✔
128
                itTimer = mActiveTimers.erase(itTimer);
110✔
129
            } else {
130
                ++itTimer;
2,160✔
131
            }
132
        }
133

134
        mTimerHandlers.erase(itHandler);
2,050✔
135
    }
136
}
2,050✔
137

138
void HsmEventDispatcherBase::startTimer(const HandlerID_t handlerID,
150✔
139
                                        const TimerID_t timerID,
140
                                        const unsigned int intervalMs,
141
                                        const bool isSingleShot) {
142
    HSM_TRACE_CALL_DEBUG_ARGS("handlerID=%d, timerID=%d, intervalMs=%d, isSingleShot=%d",
143
                              handlerID,
144
                              timerID,
145
                              intervalMs,
146
                              BOOL2INT(isSingleShot));
150✔
147
    LockGuard lck(mHandlersSync);
150✔
148

149
    if (mTimerHandlers.find(handlerID) != mTimerHandlers.end()) {
300✔
150
        auto it = mActiveTimers.find(timerID);
150✔
151

152
        if (mActiveTimers.end() != it) {
150✔
153
            it->second.handlerID = handlerID;
10✔
154
            it->second.intervalMs = intervalMs;
10✔
155
            it->second.isSingleShot = isSingleShot;
10✔
156

157
            // restart timer
158
            stopTimerImpl(timerID);
10✔
159
            startTimerImpl(timerID, it->second.intervalMs, it->second.isSingleShot);
10✔
160
        } else {
161
            TimerInfo newTimer;
140✔
162

163
            newTimer.handlerID = handlerID;
140✔
164
            newTimer.intervalMs = intervalMs;
140✔
165
            newTimer.isSingleShot = isSingleShot;
140✔
166

167
            mActiveTimers.emplace(timerID, newTimer);
140✔
168
            startTimerImpl(timerID, intervalMs, isSingleShot);
140✔
169
        }
170
    }
171
}
150✔
172

173
void HsmEventDispatcherBase::restartTimer(const TimerID_t timerID) {
20✔
174
    HSM_TRACE_CALL_DEBUG_ARGS("timerID=%d", SC2INT(timerID));
20✔
175
    LockGuard lck(mHandlersSync);
20✔
176
    auto it = mActiveTimers.find(timerID);
20✔
177

178
    if (mActiveTimers.end() != it) {
20✔
179
        stopTimerImpl(timerID);
20✔
180
        startTimerImpl(timerID, it->second.intervalMs, it->second.isSingleShot);
20✔
181
    }
182
}
20✔
183

184
void HsmEventDispatcherBase::stopTimer(const TimerID_t timerID) {
30✔
185
    HSM_TRACE_CALL_DEBUG_ARGS("timerID=%d", SC2INT(timerID));
30✔
186
    LockGuard lck(mHandlersSync);
30✔
187
    auto it = mActiveTimers.find(timerID);
30✔
188

189
    HSM_TRACE_DEBUG("mActiveTimers=%lu", mActiveTimers.size());
30✔
190

191
    if (mActiveTimers.end() != it) {
30✔
192
        stopTimerImpl(timerID);
30✔
193
        mActiveTimers.erase(it);
30✔
194
    }
195
}
30✔
196

197
bool HsmEventDispatcherBase::isTimerRunning(const TimerID_t timerID) {
30✔
198
    return (mActiveTimers.find(timerID) != mActiveTimers.end());
30✔
199
}
200

201
int HsmEventDispatcherBase::getNextHandlerID() {
6,300✔
202
    return mNextHandlerId++;
6,300✔
203
}
204

205
void HsmEventDispatcherBase::unregisterAllEventHandlers() {
399✔
206
    LockGuard lck(mHandlersSync);
399✔
207
    mEventHandlers.clear();
399✔
208
}
399✔
209

210
EnqueuedEventHandlerFunc_t HsmEventDispatcherBase::getEnqueuedEventHandlerFunc(const HandlerID_t handlerID) const {
10✔
211
    // cppcheck-suppress misra-c2012-17.7 ; false-positive. This a function pointer, not function call.
212
    EnqueuedEventHandlerFunc_t func;
10✔
213
    auto it = mEnqueuedEventHandlers.find(handlerID);
10✔
214

215
    if (mEnqueuedEventHandlers.end() != it) {
10✔
216
        func = it->second;
10✔
217
    }
218

219
    return func;
10✔
220
}
×
221

222
HsmEventDispatcherBase::TimerInfo HsmEventDispatcherBase::getTimerInfo(const TimerID_t timerID) const {
130✔
223
    TimerInfo result;
130✔
224
    auto it = mActiveTimers.find(timerID);
130✔
225

226
    if (mActiveTimers.end() != it) {
130✔
227
        result = it->second;
130✔
228
    }
229

230
    return result;
130✔
231
}
232

233
TimerHandlerFunc_t HsmEventDispatcherBase::getTimerHandlerFunc(const HandlerID_t handlerID) const {
130✔
234
    // cppcheck-suppress misra-c2012-17.7 ; false-positive. This a function pointer, not function call.
235
    TimerHandlerFunc_t func;
130✔
236
    auto it = mTimerHandlers.find(handlerID);
130✔
237

238
    if (mTimerHandlers.end() != it) {
130✔
239
        func = it->second;
130✔
240
    }
241

242
    return func;
130✔
243
}
×
244

245
void HsmEventDispatcherBase::startTimerImpl(const TimerID_t timerID, const unsigned int intervalMs, const bool isSingleShot) {
×
246
    // do nothing. must be implemented in platfrom specific dispatcher
247
}
×
248

249
void HsmEventDispatcherBase::stopTimerImpl(const TimerID_t timerID) {
×
250
    // do nothing. must be implemented in platfrom specific dispatcher
251
}
×
252

253
bool HsmEventDispatcherBase::handleTimerEvent(const TimerID_t timerID) {
130✔
254
    HSM_TRACE_CALL_DEBUG_ARGS("timerID=%d", SC2INT(timerID));
130✔
255
    bool restartTimer = false;
130✔
256

257
    if (INVALID_HSM_TIMER_ID != timerID) {
130✔
258
        // NOTE: should lock the whole block to prevent situation when timer handler is unregistered during handler execution
259
        LockGuard lck(mHandlersSync);
130✔
260
        TimerInfo curTimer = getTimerInfo(timerID);
130✔
261

262
        HSM_TRACE_DEBUG("curTimer.handlerID=%d", curTimer.handlerID);
130✔
263

264
        if (INVALID_HSM_DISPATCHER_HANDLER_ID != curTimer.handlerID) {
130✔
265
            TimerHandlerFunc_t timerHandler = getTimerHandlerFunc(curTimer.handlerID);
130✔
266

267
            timerHandler(timerID);
130✔
268

269
            restartTimer = ((true == curTimer.isSingleShot) ? false : true);
130✔
270
        }
130✔
271
    }
130✔
272

273
    return restartTimer;
130✔
274
}
275

276
void HsmEventDispatcherBase::dispatchEnqueuedEvents() {
1,198,355✔
277
    if ((false == mStopDispatcher) && (false == mEnqueuedEvents.empty())) {
1,198,355✔
278
        HandlerID_t prevHandlerID = INVALID_HSM_DISPATCHER_HANDLER_ID;
10✔
279
        EnqueuedEventHandlerFunc_t callback;
10✔
280
        std::vector<EnqueuedEventInfo> currentEvents;
10✔
281

282
        {
10✔
283
            CriticalSection lck(mEnqueuedEventsSync);
10✔
284

285
            // copy instead of move. we want to keep memory allocated in mEnqueuedEvents
286
            currentEvents = mEnqueuedEvents;
10✔
287
            mEnqueuedEvents.clear();
10✔
288
        }
10✔
289

290
        // need to traverse events in reverse order
291
        for (auto it = currentEvents.rbegin(); (it != currentEvents.rend()) && (false == mStopDispatcher) ; ++it) {
20✔
292
            if (prevHandlerID != it->handlerID) {
10✔
293
                callback = getEnqueuedEventHandlerFunc(it->handlerID);
10✔
294
                prevHandlerID = it->handlerID;
10✔
295
            }
296

297
            callback(it->eventID);
20✔
298
        }
299
    }
20✔
300
}
1,198,355✔
301

302
void HsmEventDispatcherBase::dispatchPendingEvents() {
1,198,355✔
303
    std::list<HandlerID_t> events;
1,198,355✔
304

305
    {
1,198,355✔
306
        LockGuard lck(mEmitSync);
1,198,355✔
307
        events = std::move(mPendingEvents);
1,198,355✔
308
    }
1,198,355✔
309

310
    dispatchPendingEventsImpl(events);
1,198,355✔
311
}
1,198,355✔
312

313
void HsmEventDispatcherBase::dispatchPendingEventsImpl(const std::list<HandlerID_t>& events) {
1,198,355✔
314
    dispatchEnqueuedEvents();
1,198,355✔
315

316
    if ((false == mStopDispatcher) && (false == events.empty())) {
1,198,355✔
317
        std::map<HandlerID_t, EventHandlerFunc_t> eventHandlersCopy;
11,122✔
318

319
        {
11,122✔
320
            // TODO: workaround to prevent recursive lock if registerEventHandler/unregisterEventHandler is called from handler
321
            // callback
322
            LockGuard lck(mHandlersSync);
11,122✔
323
            eventHandlersCopy = mEventHandlers;
11,122✔
324
        }
11,122✔
325

326
        for (auto it = events.begin(); (it != events.end()) && (false == mStopDispatcher); ++it) {
1,479,573✔
327
            auto itHandler = eventHandlersCopy.find(*it);
1,468,451✔
328

329
            if (itHandler != eventHandlersCopy.end()) {
1,468,451✔
330
                // NOTE: if callback returns FALSE it means the handler doesn't want to process more events
331
                if (false == itHandler->second()) {
2,580,570✔
332
                    eventHandlersCopy.erase(itHandler);
524✔
333
                }
334
            }
335
        }
336
    }
11,122✔
337
}
1,198,355✔
338

339
}  // 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