• 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

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

4
#include "hsmcpp/HsmEventDispatcherSTD.hpp"
5

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

9
namespace hsmcpp {
10

11
#undef HSM_TRACE_CLASS
12
#define HSM_TRACE_CLASS "HsmEventDispatcherSTD"
13

14
HsmEventDispatcherSTD::HsmEventDispatcherSTD(const size_t eventsCacheSize)
64✔
15
    // cppcheck-suppress misra-c2012-10.4 ; false-positive. thinks that ':' is arithmetic operation
16
    : HsmEventDispatcherBase(eventsCacheSize) {
64✔
17
    HSM_TRACE_CALL_DEBUG();
64✔
18
}
64✔
19

20
HsmEventDispatcherSTD::~HsmEventDispatcherSTD() {
128✔
21
    HSM_TRACE_CALL_DEBUG();
64✔
22

23
    HsmEventDispatcherSTD::stop();
64✔
24
    join();
64✔
25
}
128✔
26

27
std::shared_ptr<HsmEventDispatcherSTD> HsmEventDispatcherSTD::create(const size_t eventsCacheSize) {
64✔
28
    return std::shared_ptr<HsmEventDispatcherSTD>(new HsmEventDispatcherSTD(eventsCacheSize),
64✔
29
                                                  &HsmEventDispatcherBase::handleDelete);
64✔
30
}
31

32
bool HsmEventDispatcherSTD::deleteSafe() {
64✔
33
    // NOTE: just delete the instance. Calling destructor from any thread is safe
34
    return true;
64✔
35
}
36

37
void HsmEventDispatcherSTD::emitEvent(const HandlerID_t handlerID) {
486,604✔
38
    HSM_TRACE_CALL_DEBUG();
486,604✔
39

40
    if (true == mDispatcherThread.joinable()) {
486,604✔
41
        HsmEventDispatcherBase::emitEvent(handlerID);
486,656✔
42
    }
43
}
493,116✔
44

45
bool HsmEventDispatcherSTD::start() {
868✔
46
    HSM_TRACE_CALL_DEBUG();
868✔
47
    bool result = false;
868✔
48

49
    if (false == mDispatcherThread.joinable()) {
868✔
50
        HSM_TRACE_DEBUG("starting thread...");
60✔
51
        mStopDispatcher = false;
60✔
52
        mDispatcherThread = std::thread(&HsmEventDispatcherSTD::doDispatching, this);
60✔
53
        result = mDispatcherThread.joinable();
60✔
54
    } else {
55
        result = (mDispatcherThread.get_id() != std::thread::id());
56
    }
57

58
    return result;
868✔
59
}
60

61
void HsmEventDispatcherSTD::stop() {
132✔
62
    HSM_TRACE_CALL_DEBUG();
132✔
63
    UniqueLock lck(mEmitSync);
132✔
64

65
    HsmEventDispatcherBase::stop();
132✔
66
    unregisterAllEventHandlers();
132✔
67
    notifyDispatcherAboutEvent();
132✔
68
    notifyTimersThread();
132✔
69
}
132✔
70

71
void HsmEventDispatcherSTD::join() {
64✔
72
    HSM_TRACE_CALL_DEBUG();
64✔
73

74
    if (true == mDispatcherThread.joinable()) {
64✔
75
        mDispatcherThread.join();
60✔
76
    }
77

78
    if (true == mTimersThread.joinable()) {
64✔
79
        mTimersThread.join();
4✔
80
    }
81
}
64✔
82

83
void HsmEventDispatcherSTD::startTimerImpl(const TimerID_t timerID, const unsigned int intervalMs, const bool isSingleShot) {
68✔
84
    HSM_TRACE_CALL_ARGS("timerID=%d, intervalMs=%d, isSingleShot=%d", SC2INT(timerID), intervalMs, BOOL2INT(isSingleShot));
68✔
85
    auto it = mRunningTimers.end();
68✔
86

87
    // lazy initialization of timers thread
88
    if (false == mTimersThread.joinable()) {
68✔
89
        mTimersThread = std::thread(&HsmEventDispatcherSTD::handleTimers, this);
4✔
90
    }
91

92
    {
68✔
93
        CriticalSection cs(mRunningTimersSync);
68✔
94
        it = mRunningTimers.find(timerID);
68✔
95

96
        // new timer
97
        if (mRunningTimers.end() == it) {
68✔
98
            RunningTimerInfo newTimer;
68✔
99

100
            newTimer.startedAt = std::chrono::steady_clock::now();
68✔
101
            newTimer.elapseAfter = newTimer.startedAt + std::chrono::milliseconds(intervalMs);
68✔
102

103
            mRunningTimers.emplace(timerID, newTimer);
68✔
104
        } else {
105
            // restart timer
106
            it->second.startedAt = std::chrono::steady_clock::now();
×
107
            it->second.elapseAfter = it->second.startedAt + std::chrono::milliseconds(intervalMs);
×
108
        }
109
    }
68✔
110

111
    // wakeup timers thread
112
    notifyTimersThread();
68✔
113
}
136✔
114

115
void HsmEventDispatcherSTD::stopTimerImpl(const TimerID_t timerID) {
68✔
116
    HSM_TRACE_CALL_ARGS("timerID=%d", SC2INT(timerID));
68✔
117

118
    {
68✔
119
        CriticalSection cs(mRunningTimersSync);
68✔
120
        mRunningTimers.erase(timerID);
68✔
121
    }
68✔
122

123
    // wakeup timers thread
124
    notifyTimersThread();
68✔
125
}
68✔
126

127
void HsmEventDispatcherSTD::notifyDispatcherAboutEvent() {
493,472✔
128
    mEmitEvent.notify();
493,472✔
129
}
493,468✔
130

131
void HsmEventDispatcherSTD::doDispatching() {
60✔
132
    HSM_TRACE_CALL_DEBUG();
60✔
133

134
    while (false == mStopDispatcher) {
2,316✔
135
        HsmEventDispatcherBase::dispatchPendingEvents();
2,196✔
136

137
        if (false == mStopDispatcher) {
2,196✔
138
            UniqueLock lck(mEmitSync);
2,156✔
139

140
            if (true == mPendingEvents.empty()) {
2,156✔
141
                HSM_TRACE_DEBUG("wait for emit...");
900✔
142
                // NOTE: false-positive. "A function should have a single point of exit at the end" is not vialated because
143
                //       "return" statement belogs to a lamda function, not doDispatching.
144
                // cppcheck-suppress misra-c2012-15.5
145
                mEmitEvent.wait(lck, [=]() {
900✔
146
                    // cppcheck-suppress misra-c2012-15.5 ; false-positive. "return" statement belongs to lambda function
147
                    return (false == mPendingEvents.empty()) || (false == mEnqueuedEvents.empty()) || (true == mStopDispatcher);
1,800✔
148
                });
149
                HSM_TRACE_DEBUG("woke up. pending events=%lu", mPendingEvents.size());
900✔
150
            }
151
        }
2,156✔
152
    }
153

154
    HSM_TRACE_DEBUG("EXIT");
60✔
155
}
60✔
156

157
void HsmEventDispatcherSTD::notifyTimersThread() {
268✔
158
    HSM_TRACE_CALL_DEBUG();
268✔
159
    mNotifiedTimersThread = true;
268✔
160
    mTimerEvent.notify();
268✔
161
}
268✔
162

163
void HsmEventDispatcherSTD::handleTimers() {
4✔
164
    HSM_TRACE_CALL_DEBUG();
4✔
165
    Mutex timerEventSync;
4✔
166
    UniqueLock lck(timerEventSync);
4✔
167

168
    while (false == mStopDispatcher) {
196✔
169
        mRunningTimersSync.lock();
192✔
170

171
        if (false == mRunningTimers.empty()) {
192✔
172
            auto itTimeout = mRunningTimers.begin();
124✔
173

174
            for (auto it = mRunningTimers.begin(); it != mRunningTimers.end(); ++it) {
264✔
175
                if (it->second.elapseAfter < itTimeout->second.elapseAfter) {
140✔
176
                    itTimeout = it;
8✔
177
                }
178
            }
179

180
            TimerID_t waitingTimerId = itTimeout->first;
124✔
181
            const int intervalMs = std::chrono::duration_cast<std::chrono::milliseconds>(itTimeout->second.elapseAfter -
124✔
182
                                                                                         std::chrono::steady_clock::now())
124✔
183
                                       .count();
124✔
184

185
            mRunningTimersSync.unlock();
124✔
186

187
            // NOTE: false-positive. "A function should have a single point of exit at the end" is not vialated because
188
            //       "return" statement belogs to a lamda function, not doDispatching.
189
            // cppcheck-suppress misra-c2012-15.5
190
            const bool waitResult = mTimerEvent.wait_for(lck, intervalMs, [&]() { return mNotifiedTimersThread; });
124✔
191

192
            mNotifiedTimersThread = false;
124✔
193

194
            if (false == waitResult) {
124✔
195
                // timeout expired
196
                CriticalSection lckExpired(mRunningTimersSync);
52✔
197

198
                itTimeout = mRunningTimers.find(waitingTimerId);
52✔
199

200
                if (itTimeout != mRunningTimers.end()) {
52✔
201
                    if (true == handleTimerEvent(waitingTimerId)) {
52✔
202
                        // restart timer
203
                        itTimeout->second.startedAt = std::chrono::steady_clock::now();
16✔
204
                        itTimeout->second.elapseAfter = itTimeout->second.startedAt + std::chrono::milliseconds(intervalMs);
16✔
205
                    } else {
206
                        // single shot timer. remove from queue
207
                        mRunningTimers.erase(itTimeout);
36✔
208
                    }
209
                } else {
210
                    // do nothing
211
                }
212
            } else {
52✔
213
                // thread was woken up by start/stop operation. no need to do anything
214
            }
215
        } else {
216
            mRunningTimersSync.unlock();
68✔
217

218
            // wait for timer events
219
            mTimerEvent.wait(lck);
136✔
220
        }
221
    }
222

223
    HSM_TRACE_DEBUG("EXIT");
4✔
224
}
4✔
225

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