• 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

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

4
#include "hsmcpp/HsmEventDispatcherGLib.hpp"
5

6
#include <unistd.h>
7

8
#include "hsmcpp/logging.hpp"
9
#include "hsmcpp/os/CriticalSection.hpp"
10

11
namespace hsmcpp {
12

13
#undef HSM_TRACE_CLASS
14
#define HSM_TRACE_CLASS "HsmEventDispatcherGLib"
15

16
HsmEventDispatcherGLib::HsmEventDispatcherGLib(const size_t eventsCacheSize)
48✔
17
    // NOTE: false-positive. thinks that ':' is arithmetic operation
18
    // cppcheck-suppress misra-c2012-10.4
19
    : HsmEventDispatcherBase(eventsCacheSize) {}
48✔
20

21
HsmEventDispatcherGLib::HsmEventDispatcherGLib(GMainContext* context, const size_t eventsCacheSize)
×
22
    // NOTE: false-positive. thinks that ':' is arithmetic operation
23
    // cppcheck-suppress misra-c2012-10.4
24
    : HsmEventDispatcherBase(eventsCacheSize)
25
    , mContext(context) {}
×
26

27
HsmEventDispatcherGLib::~HsmEventDispatcherGLib() {
90✔
28
    HSM_TRACE_CALL();
45✔
29

30
    HsmEventDispatcherGLib::stop();
45✔
31
}
90✔
32

33
std::shared_ptr<HsmEventDispatcherGLib> HsmEventDispatcherGLib::create(const size_t eventsCacheSize) {
48✔
34
    return std::shared_ptr<HsmEventDispatcherGLib>(new HsmEventDispatcherGLib(eventsCacheSize),
48✔
35
                                                   &HsmEventDispatcherBase::handleDelete);
48✔
36
}
37

38
std::shared_ptr<HsmEventDispatcherGLib> HsmEventDispatcherGLib::create(GMainContext* context, const size_t eventsCacheSize) {
×
39
    return std::shared_ptr<HsmEventDispatcherGLib>(new HsmEventDispatcherGLib(context, eventsCacheSize),
×
40
                                                   &HsmEventDispatcherBase::handleDelete);
×
41
}
42

43
bool HsmEventDispatcherGLib::deleteSafe() {
48✔
44
    g_idle_add(
48✔
45
        // cppcheck-suppress misra-c2012-13.1 ; false-positive. this is a functor, not initializer list
46
        [](void* data) {
48✔
47
            if (nullptr != data) {
48
                HsmEventDispatcherGLib* pThis = reinterpret_cast<HsmEventDispatcherGLib*>(data);
49

50
                pThis->stop();
51
                delete pThis;
52
            }
53

54
            // NOTE: false-positive. "return" statement belongs to lambda function, not parent function
55
            // cppcheck-suppress misra-c2012-15.5
56
            return G_SOURCE_REMOVE;
57
        },
58
        this);
59

60
    return false;
48✔
61
}
62

63
bool HsmEventDispatcherGLib::start() {
633✔
64
    HSM_TRACE_CALL_DEBUG();
633✔
65
    bool result = false;
633✔
66

67
    // check if dispatcher was already started
68
    if ((-1) == mPipeFD[0]) {
633✔
69
        int rc = pipe(mPipeFD);
45✔
70

71
        if (0 == rc) {
45✔
72
            mReadChannel = g_io_channel_unix_new(mPipeFD[0]);
45✔
73

74
            if (nullptr != mReadChannel) {
45✔
75
                mIoSource = g_io_create_watch(mReadChannel, static_cast<GIOCondition>(G_IO_IN | G_IO_HUP));
45✔
76

77
                if (nullptr != mIoSource) {
45✔
78
                    g_source_set_callback(mIoSource, reinterpret_cast<GSourceFunc>(onPipeDataAvailable), this, nullptr);
45✔
79
                    g_source_attach(mIoSource, mContext);
45✔
80
                    result = true;
45✔
81
                } else {
82
                    HSM_TRACE_ERROR("failed to create io source");
83
                }
84
            } else {
85
                HSM_TRACE_ERROR("failed to create io channel");
86
            }
87
        } else {
88
            HSM_TRACE_ERROR("failed to create pipe (errno=%d)", errno);
45✔
89
        }
90

91
        if (false == result) {
45✔
92
            if (nullptr != mReadChannel) {
×
93
                g_io_channel_unref(mReadChannel);
×
94
                mReadChannel = nullptr;
×
95
            }
96

97
            if ((-1) == mPipeFD[0]) {
×
98
                close(mPipeFD[0]);
×
99
                close(mPipeFD[1]);
×
100
                mPipeFD[0] = -1;
×
101
                mPipeFD[1] = -1;
×
102
            }
103
        }
104
    } else {
105
        result = true;
106
    }
107

108
    return result;
633✔
109
}
110

111
void HsmEventDispatcherGLib::stop() {
141✔
112
    HsmEventDispatcherBase::stop();
141✔
113
    unregisterAllTimerHandlers();
141✔
114
    unregisterAllEventHandlers();
141✔
115

116
    if (nullptr != mIoSource) {
141✔
117
        g_source_destroy(mIoSource);
45✔
118
        g_source_unref(mIoSource);
45✔
119
        mIoSource = nullptr;
45✔
120
    }
121

122
    if (nullptr != mReadChannel) {
141✔
123
        g_io_channel_unref(mReadChannel);
45✔
124
        mReadChannel = nullptr;
45✔
125
        close(mPipeFD[0]);
45✔
126
        close(mPipeFD[1]);
45✔
127
        mPipeFD[0] = -1;
45✔
128
        mPipeFD[1] = -1;
45✔
129
    }
130
}
141✔
131

132
void HsmEventDispatcherGLib::emitEvent(const HandlerID_t handlerID) {
599,898✔
133
    HSM_TRACE_CALL();
599,898✔
134

135
    if (mPipeFD[1] > 0) {
599,898✔
136
        HsmEventDispatcherBase::emitEvent(handlerID);
599,898✔
137
    }
138
}
600,660✔
139

140
void HsmEventDispatcherGLib::unregisterAllTimerHandlers() {
141✔
141
    CriticalSection lckExpired(mRunningTimersSync);
141✔
142

143
    for (auto it = mNativeTimerHandlers.begin(); it != mNativeTimerHandlers.end(); ++it) {
141✔
144
        g_source_destroy(it->second);
×
145
        g_source_unref(it->second);
×
146
    }
147

148
    mNativeTimerHandlers.clear();
141✔
149
}
141✔
150

151
void HsmEventDispatcherGLib::startTimerImpl(const TimerID_t timerID, const unsigned int intervalMs, const bool isSingleShot) {
51✔
152
    HSM_TRACE_CALL_DEBUG_ARGS("timerID=%d, intervalMs=%d, isSingleShot=%d",
153
                              SC2INT(timerID),
154
                              intervalMs,
155
                              BOOL2INT(isSingleShot));
51✔
156
    CriticalSection lckExpired(mRunningTimersSync);
51✔
157
    auto it = mNativeTimerHandlers.find(timerID);
51✔
158

159
    if (mNativeTimerHandlers.end() == it) {
51✔
160
        GSource* timeoutSource = g_timeout_source_new(intervalMs);
51✔
161

162
        g_source_set_callback(timeoutSource,
51✔
163
                              G_SOURCE_FUNC(&HsmEventDispatcherGLib::onTimerEvent),
164
                              new TimerData_t(this, timerID),
51✔
165
                              &HsmEventDispatcherGLib::onFreeTimerData);
166

167
        g_source_attach(timeoutSource, mContext);
51✔
168
        mNativeTimerHandlers.emplace(timerID, timeoutSource);
51✔
169
    } else {
170
        HSM_TRACE_ERROR("timer with id=%d already exists", timerID);
51✔
171
    }
172
}
51✔
173

174
void HsmEventDispatcherGLib::stopTimerImpl(const TimerID_t timerID) {
51✔
175
    HSM_TRACE_CALL_DEBUG_ARGS("timerID=%d", SC2INT(timerID));
51✔
176
    CriticalSection lckExpired(mRunningTimersSync);
51✔
177
    auto it = mNativeTimerHandlers.find(timerID);
51✔
178

179
    if (mNativeTimerHandlers.end() != it) {
51✔
180
        g_source_destroy(it->second);
24✔
181
        g_source_unref(it->second);
24✔
182
        mNativeTimerHandlers.erase(it);
24✔
183
    }
184
}
51✔
185

186
gboolean HsmEventDispatcherGLib::onTimerEvent(const TimerData_t* timerData) {
39✔
187
    bool restartTimer = false;
39✔
188

189
    if (nullptr != timerData) {
39✔
190
        restartTimer = timerData->first->handleTimerEvent(timerData->second);
39✔
191

192
        if (false == restartTimer) {
39✔
193
            CriticalSection lckExpired(timerData->first->mRunningTimersSync);
27✔
194
            auto itTimer = timerData->first->mNativeTimerHandlers.find(timerData->second);
27✔
195

196
            if (timerData->first->mNativeTimerHandlers.end() != itTimer) {
27✔
197
                g_source_unref(itTimer->second);
27✔
198
                timerData->first->mNativeTimerHandlers.erase(itTimer);
27✔
199
            } else {
200
                HSM_TRACE_ERROR("unexpected error. timer not found");
27✔
201
            }
202
        }
27✔
203
    }
204

205
    return restartTimer;
39✔
206
}
207

208
void HsmEventDispatcherGLib::onFreeTimerData(void* timerData) {
51✔
209
    delete reinterpret_cast<TimerData_t*>(timerData);
51✔
210
}
51✔
211

212
void HsmEventDispatcherGLib::notifyDispatcherAboutEvent() {
600,663✔
213
    std::lock_guard<std::mutex> lck(mPipeSync);
600,663✔
214
    char dummy = 1;
600,663✔
215

216
    // we just need to trigger the callback. there is no need to pass any real data there
217
    // TODO: should we check for result?
218
    write(mPipeFD[1], &dummy, sizeof(dummy));
600,663✔
219
}
600,663✔
220

221
gboolean HsmEventDispatcherGLib::onPipeDataAvailable(GIOChannel* gio, GIOCondition condition, gpointer data) {
600,603✔
222
    HSM_TRACE_CALL();
600,603✔
223
    gboolean continueDispatching = TRUE;
600,603✔
224
    HsmEventDispatcherGLib* pThis = static_cast<HsmEventDispatcherGLib*>(data);
600,603✔
225

226
    if (false == pThis->mStopDispatcher) {
600,603✔
227
        pThis->mDispatchingIterationRunning = true;
600,603✔
228

229
        HSM_TRACE_DEBUG("condition=%d, G_IO_HUP=%s, G_IO_IN=%s",
230
                        static_cast<int>(condition),
231
                        BOOL2STR(condition & G_IO_HUP),
232
                        BOOL2STR(condition & G_IO_IN));
600,603✔
233

234
        if (!(condition & G_IO_HUP)) {
600,603✔
235
            char dummy;
600,603✔
236
            int bytes = read(pThis->mPipeFD[0], &dummy, sizeof(dummy));
600,603✔
237

238
            if (1 == bytes) {
600,603✔
239
                pThis->dispatchPendingEvents();
600,603✔
240
            }
241
        }
242

243
        if (true == pThis->mStopDispatcher) {
600,603✔
244
            continueDispatching = FALSE;
×
245
            pThis->mDispatchingDoneEvent.notify_one();
×
246
        }
247

248
        pThis->mDispatchingIterationRunning = false;
600,603✔
249
    } else {
250
        continueDispatching = FALSE;
251
    }
252

253
    return continueDispatching;
600,603✔
254
}
255

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