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

igor-krechetov / hsmcpp / 4443063091

pending completion
4443063091

push

github

igor-krechetov
[0.31.0][r] ArduinoIDE support

1791 of 2199 relevant lines covered (81.45%)

2430.76 hits per line

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

95.7
/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) {
1,059✔
16
    mEnqueuedEvents.reserve(eventsCacheSize);
1,059✔
17
}
1,059✔
18

19
HsmEventDispatcherBase::~HsmEventDispatcherBase() {}
3,177✔
20

21
HandlerID_t HsmEventDispatcherBase::registerEventHandler(const EventHandlerFunc_t& handler) {
1,059✔
22
    HSM_TRACE_CALL_DEBUG();
1,059✔
23
    HandlerID_t id = getNextHandlerID();
1,059✔
24
    LockGuard lck(mHandlersSync);
1,059✔
25

26
    mEventHandlers.emplace(id, handler);
1,059✔
27

28
    return id;
1,059✔
29
}
1,059✔
30

31
void HsmEventDispatcherBase::unregisterEventHandler(const HandlerID_t handlerID) {
1,059✔
32
    HSM_TRACE_CALL_DEBUG_ARGS("handlerID=%d", handlerID);
1,059✔
33
    LockGuard lck(mHandlersSync);
1,059✔
34

35
    mEventHandlers.erase(handlerID);
1,059✔
36
}
1,059✔
37

38
void HsmEventDispatcherBase::emitEvent(const HandlerID_t handlerID) {
18,623✔
39
    HSM_TRACE_CALL_DEBUG();
18,623✔
40

41
    {
18,623✔
42
        LockGuard lck(mEmitSync);
18,623✔
43
        mPendingEvents.push_back(handlerID);
18,842✔
44
    }
18,842✔
45

46
    notifyDispatcherAboutEvent();
18,822✔
47

48
    // NOTE: this is not a full implementation. child classes must implement additional logic
49
}
18,814✔
50

51
bool HsmEventDispatcherBase::enqueueEvent(const HandlerID_t handlerID, const EventID_t event) {
10✔
52
    bool wasAdded = false;
10✔
53

54
    if (mEnqueuedEvents.size() < mEnqueuedEvents.capacity()) {
10✔
55
        EnqueuedEventInfo newEvent;
10✔
56

57
        newEvent.handlerID = handlerID;
10✔
58
        newEvent.eventID = event;
10✔
59

60
        {
10✔
61
            CriticalSection cs(mEnqueuedEventsSync);
10✔
62
            mEnqueuedEvents.push_back(newEvent);
10✔
63
        }
10✔
64

65
        wasAdded = true;
10✔
66
        notifyDispatcherAboutEvent();
10✔
67
    }
68

69
    return wasAdded;
10✔
70
}
71

72
HandlerID_t HsmEventDispatcherBase::registerEnqueuedEventHandler(const EnqueuedEventHandlerFunc_t& handler) {
1,059✔
73
    HSM_TRACE_CALL_DEBUG();
1,059✔
74
    HandlerID_t id = getNextHandlerID();
1,059✔
75
    LockGuard lck(mHandlersSync);
1,059✔
76

77
    mEnqueuedEventHandlers.emplace(id, handler);
1,059✔
78

79
    return id;
1,059✔
80
}
1,059✔
81

82
void HsmEventDispatcherBase::unregisterEnqueuedEventHandler(const HandlerID_t handlerID) {
1,059✔
83
    HSM_TRACE_CALL_DEBUG_ARGS("handlerID=%d", handlerID);
1,059✔
84
    LockGuard lck(mHandlersSync);
1,059✔
85

86
    mEnqueuedEventHandlers.erase(handlerID);
1,059✔
87
}
1,059✔
88

89
HandlerID_t HsmEventDispatcherBase::registerTimerHandler(const TimerHandlerFunc_t& handler) {
1,059✔
90
    const HandlerID_t newID = getNextHandlerID();
1,059✔
91
    LockGuard lck(mHandlersSync);
1,059✔
92

93
    mTimerHandlers.emplace(newID, handler);
1,059✔
94

95
    return newID;
1,059✔
96
}
1,059✔
97

98
void HsmEventDispatcherBase::unregisterTimerHandler(const HandlerID_t handlerID) {
1,059✔
99
    LockGuard lck(mHandlersSync);
1,059✔
100
    auto itHandler = mTimerHandlers.find(handlerID);
1,059✔
101

102
    if (mTimerHandlers.end() != itHandler) {
1,059✔
103
        for (auto itTimer = mActiveTimers.begin(); itTimer != mActiveTimers.end();) {
1,059✔
104
            if (handlerID == itTimer->second.handlerID) {
110✔
105
                stopTimerImpl(itTimer->first);
110✔
106
                itTimer = mActiveTimers.erase(itTimer);
110✔
107
            } else {
108
                ++itTimer;
1,169✔
109
            }
110
        }
111

112
        mTimerHandlers.erase(itHandler);
1,059✔
113
    }
114
}
1,059✔
115

116
void HsmEventDispatcherBase::startTimer(const HandlerID_t handlerID,
140✔
117
                                        const TimerID_t timerID,
118
                                        const unsigned int intervalMs,
119
                                        const bool isSingleShot) {
120
    HSM_TRACE_CALL_DEBUG_ARGS("handlerID=%d, timerID=%d, intervalMs=%d, isSingleShot=%d",
121
                              handlerID,
122
                              timerID,
123
                              intervalMs,
124
                              BOOL2INT(isSingleShot));
140✔
125
    LockGuard lck(mHandlersSync);
140✔
126

127
    if (mTimerHandlers.find(handlerID) != mTimerHandlers.end()) {
280✔
128
        auto it = mActiveTimers.find(timerID);
140✔
129

130
        if (mActiveTimers.end() != it) {
140✔
131
            it->second.handlerID = handlerID;
10✔
132
            it->second.intervalMs = intervalMs;
10✔
133
            it->second.isSingleShot = isSingleShot;
10✔
134

135
            // restart timer
136
            stopTimerImpl(timerID);
10✔
137
            startTimerImpl(timerID, it->second.intervalMs, it->second.isSingleShot);
10✔
138
        } else {
139
            TimerInfo newTimer;
130✔
140

141
            newTimer.handlerID = handlerID;
130✔
142
            newTimer.intervalMs = intervalMs;
130✔
143
            newTimer.isSingleShot = isSingleShot;
130✔
144

145
            mActiveTimers.emplace(timerID, newTimer);
130✔
146
            startTimerImpl(timerID, intervalMs, isSingleShot);
130✔
147
        }
148
    }
149
}
140✔
150

151
void HsmEventDispatcherBase::restartTimer(const TimerID_t timerID) {
20✔
152
    HSM_TRACE_CALL_DEBUG_ARGS("timerID=%d", SC2INT(timerID));
20✔
153
    LockGuard lck(mHandlersSync);
20✔
154
    auto it = mActiveTimers.find(timerID);
20✔
155

156
    if (mActiveTimers.end() != it) {
20✔
157
        stopTimerImpl(timerID);
20✔
158
        startTimerImpl(timerID, it->second.intervalMs, it->second.isSingleShot);
20✔
159
    }
160
}
20✔
161

162
void HsmEventDispatcherBase::stopTimer(const TimerID_t timerID) {
20✔
163
    HSM_TRACE_CALL_DEBUG_ARGS("timerID=%d", SC2INT(timerID));
20✔
164
    LockGuard lck(mHandlersSync);
20✔
165
    auto it = mActiveTimers.find(timerID);
20✔
166

167
    HSM_TRACE_DEBUG("mActiveTimers=%lu", mActiveTimers.size());
20✔
168

169
    if (mActiveTimers.end() != it) {
20✔
170
        stopTimerImpl(timerID);
20✔
171
        mActiveTimers.erase(it);
20✔
172
    }
173
}
20✔
174

175
bool HsmEventDispatcherBase::isTimerRunning(const TimerID_t timerID) {
×
176
    return (mActiveTimers.find(timerID) != mActiveTimers.end());
×
177
}
178

179
int HsmEventDispatcherBase::getNextHandlerID() {
3,177✔
180
    return mNextHandlerId++;
3,177✔
181
}
182

183
void HsmEventDispatcherBase::unregisterAllEventHandlers() {
1,059✔
184
    LockGuard lck(mHandlersSync);
1,059✔
185
    mEventHandlers.clear();
1,059✔
186
}
1,059✔
187

188
EnqueuedEventHandlerFunc_t HsmEventDispatcherBase::getEnqueuedEventHandlerFunc(const HandlerID_t handlerID) const {
10✔
189
    EnqueuedEventHandlerFunc_t func;
10✔
190
    auto it = mEnqueuedEventHandlers.find(handlerID);
10✔
191

192
    if (mEnqueuedEventHandlers.end() != it) {
10✔
193
        func = it->second;
10✔
194
    }
195

196
    return func;
10✔
197
}
×
198

199
HsmEventDispatcherBase::TimerInfo HsmEventDispatcherBase::getTimerInfo(const TimerID_t timerID) const {
130✔
200
    TimerInfo result;
130✔
201
    auto it = mActiveTimers.find(timerID);
130✔
202

203
    if (mActiveTimers.end() != it) {
130✔
204
        result = it->second;
130✔
205
    }
206

207
    return result;
130✔
208
}
209

210
TimerHandlerFunc_t HsmEventDispatcherBase::getTimerHandlerFunc(const HandlerID_t handlerID) const {
130✔
211
    TimerHandlerFunc_t func;
130✔
212
    auto it = mTimerHandlers.find(handlerID);
130✔
213

214
    if (mTimerHandlers.end() != it) {
130✔
215
        func = it->second;
130✔
216
    }
217

218
    return func;
130✔
219
}
×
220

221
void HsmEventDispatcherBase::startTimerImpl(const TimerID_t timerID, const unsigned int intervalMs, const bool isSingleShot) {
×
222
    // do nothing. must be implemented in platfrom specific dispatcher
223
}
×
224

225
void HsmEventDispatcherBase::stopTimerImpl(const TimerID_t timerID) {
×
226
    // do nothing. must be implemented in platfrom specific dispatcher
227
}
×
228

229
bool HsmEventDispatcherBase::handleTimerEvent(const TimerID_t timerID) {
130✔
230
    HSM_TRACE_CALL_DEBUG_ARGS("timerID=%d", SC2INT(timerID));
130✔
231
    bool restartTimer = false;
130✔
232

233
    if (INVALID_HSM_TIMER_ID != timerID) {
130✔
234
        // NOTE: should lock the whole block to prevent situation when timer handler is unregistered during handler execution
235
        LockGuard lck(mHandlersSync);
130✔
236
        TimerInfo curTimer = getTimerInfo(timerID);
130✔
237

238
        HSM_TRACE_DEBUG("curTimer.handlerID=%d", curTimer.handlerID);
130✔
239

240
        if (INVALID_HSM_DISPATCHER_HANDLER_ID != curTimer.handlerID) {
130✔
241
            TimerHandlerFunc_t timerHandler = getTimerHandlerFunc(curTimer.handlerID);
130✔
242

243
            timerHandler(timerID);
130✔
244

245
            restartTimer = ((true == curTimer.isSingleShot) ? false : true);
130✔
246
        }
130✔
247
    }
130✔
248

249
    return restartTimer;
130✔
250
}
251

252
void HsmEventDispatcherBase::dispatchEnqueuedEvents() {
13,671✔
253
    if (false == mEnqueuedEvents.empty()) {
13,671✔
254
        HandlerID_t prevHandlerID = INVALID_HSM_DISPATCHER_HANDLER_ID;
10✔
255
        EnqueuedEventHandlerFunc_t callback;
10✔
256
        std::vector<EnqueuedEventInfo> currentEvents;
10✔
257

258
        {
10✔
259
            CriticalSection lck(mEnqueuedEventsSync);
10✔
260

261
            // copy instead of move. we want to keep memory allocated in mEnqueuedEvents
262
            currentEvents = mEnqueuedEvents;
10✔
263
            mEnqueuedEvents.clear();
10✔
264
        }
10✔
265

266
        // need to traverse events in reverce order
267
        for (auto it = currentEvents.rbegin(); it != currentEvents.rend(); ++it) {
20✔
268
            if (prevHandlerID != it->handlerID) {
10✔
269
                callback = getEnqueuedEventHandlerFunc(it->handlerID);
10✔
270
                prevHandlerID = it->handlerID;
10✔
271
            }
272

273
            callback(it->eventID);
20✔
274
        }
275
    }
20✔
276
}
13,671✔
277

278
void HsmEventDispatcherBase::dispatchPendingEvents() {
13,671✔
279
    std::list<HandlerID_t> events;
13,671✔
280

281
    {
13,671✔
282
        LockGuard lck(mEmitSync);
13,671✔
283
        events = std::move(mPendingEvents);
13,671✔
284
    }
13,671✔
285

286
    dispatchPendingEventsImpl(events);
13,671✔
287
}
13,671✔
288

289
void HsmEventDispatcherBase::dispatchPendingEventsImpl(const std::list<HandlerID_t>& events) {
13,671✔
290
    dispatchEnqueuedEvents();
13,671✔
291

292
    if (false == events.empty()) {
13,671✔
293
        std::map<HandlerID_t, EventHandlerFunc_t> eventHandlersCopy;
3,036✔
294

295
        {
3,036✔
296
            // TODO: workaround to prevent recursive lock if registerEventHandler/unregisterEventHandler is called from handler
297
            // callback
298
            LockGuard lck(mHandlersSync);
3,036✔
299
            eventHandlersCopy = mEventHandlers;
3,036✔
300
        }
3,036✔
301

302
        for (auto it = events.begin(); it != events.end(); ++it) {
18,041✔
303
            auto itHandler = eventHandlersCopy.find(*it);
15,005✔
304

305
            if (itHandler != eventHandlersCopy.end()) {
15,005✔
306
                itHandler->second();
30,010✔
307
            }
308
        }
309
    }
3,036✔
310
}
13,671✔
311

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