FlightGear next
dbusdispatcher.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
3 * SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#include "dbusdispatcher.h"
8#include "dbusconnection.h"
9#include <algorithm>
10
11namespace { // anonymous namespace
12
13template <typename T, typename... Args>
14std::unique_ptr<T> our_make_unique(Args&&... args)
15{
16 return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
17}
18
19} // end of anonymous namespace
20
21namespace flightgear::swift {
22
26 void operator()(event* obj) const
27 {
28 event_del(obj);
29 event_free(obj);
30 }
31};
32
35{
36public:
38 WatchHandler(event_base* base, DBusWatch* watch)
39 : m_base(base), m_watch(watch)
40 {
41 const unsigned int flags = dbus_watch_get_flags(watch);
42 short monitoredEvents = EV_PERSIST;
43
44 if (flags & DBUS_WATCH_READABLE) { monitoredEvents |= EV_READ; }
45 if (flags & DBUS_WATCH_WRITABLE) { monitoredEvents |= EV_WRITE; }
46
47 const int fd = dbus_watch_get_unix_fd(watch);
48 m_event.reset(event_new(m_base, fd, monitoredEvents, callback, this));
49 event_add(m_event.get(), nullptr);
50 }
51
53 DBusWatch* getWatch() { return m_watch; }
54
56 const DBusWatch* getWatch() const { return m_watch; }
57
58private:
60 static void callback(evutil_socket_t fd, short event, void* data)
61 {
62 (void)fd; // Not really unused, but GCC/Clang still complain about it.
63 auto* watchHandler = static_cast<WatchHandler*>(data);
64
65 unsigned int flags = 0;
66 if (event & EV_READ) { flags |= DBUS_WATCH_READABLE; }
67 if (event & EV_WRITE) { flags |= DBUS_WATCH_WRITABLE; }
68 dbus_watch_handle(watchHandler->m_watch, flags);
69 }
70
71 event_base* m_base = nullptr;
72 std::unique_ptr<event, EventDeleter> m_event;
73 DBusWatch* m_watch = nullptr;
74};
75
78{
79public:
81 TimeoutHandler(event_base* base, DBusTimeout* timeout)
82 : m_base(base), m_timeout(timeout)
83 {
84 timeval timer;
85 const int interval = dbus_timeout_get_interval(timeout);
86 timer.tv_sec = interval / 1000;
87 timer.tv_usec = (interval % 1000) * 1000;
88
89 m_event.reset(evtimer_new(m_base, callback, this));
90 evtimer_add(m_event.get(), &timer);
91 }
92
94 const DBusTimeout* getTimeout() const { return m_timeout; }
95
96private:
98 static void callback(evutil_socket_t fd, short event, void* data)
99 {
100 (void)fd; // unused
101 (void)event; // unused
102 auto* timeoutHandler = static_cast<TimeoutHandler*>(data);
103 dbus_timeout_handle(timeoutHandler->m_timeout);
104 }
105
106 event_base* m_base = nullptr;
107 std::unique_ptr<event, EventDeleter> m_event;
108 DBusTimeout* m_timeout = nullptr;
109};
110
112class Timer
113{
114public:
115 Timer() = default;
117 Timer(event_base* base, const timeval& timeout, const std::function<void()>& func)
118 : m_base(base), m_func(func)
119 {
120 m_event.reset(evtimer_new(m_base, callback, this));
121 evtimer_add(m_event.get(), &timeout);
122 }
123
124private:
126 static void callback(evutil_socket_t fd, short event, void* data)
127 {
128 (void)fd; // unused
129 (void)event; // unused
130 auto* timer = static_cast<Timer*>(data);
131 timer->m_func();
132 delete timer;
133 }
134
135 event_base* m_base = nullptr;
136 std::unique_ptr<event, EventDeleter> m_event;
137 std::function<void()> m_func;
138};
139
140CDBusDispatcher::CDBusDispatcher() : m_eventBase(event_base_new())
141{
142 using namespace std::placeholders;
143 m_watchCallbacks = WatchCallbacks(std::bind(&CDBusDispatcher::dbusAddWatch, this, _1),
144 std::bind(&CDBusDispatcher::dbusRemoveWatch, this, _1),
145 std::bind(&CDBusDispatcher::dbusWatchToggled, this, _1));
146
147 m_timeoutCallbacks = TimeoutCallbacks(std::bind(&CDBusDispatcher::dbusAddTimeout, this, _1),
148 std::bind(&CDBusDispatcher::dbusRemoveTimeout, this, _1),
149 std::bind(&CDBusDispatcher::dbusTimeoutToggled, this, _1));
150}
151
155
157{
158 m_dispatchList.push_back(dispatchable);
159}
160
162{
163 auto it = std::find(m_dispatchList.begin(), m_dispatchList.end(), dispatchable);
164 if (it != m_dispatchList.end()) { m_dispatchList.erase(it); }
165}
166
168{
169 if (!m_eventBase) { return; }
170 event_base_dispatch(m_eventBase.get());
171}
172
174{
175 if (!m_eventBase) { return; }
176 event_base_loop(m_eventBase.get(), EVLOOP_NONBLOCK);
177 dispatch();
178}
179
180void CDBusDispatcher::dispatch()
181{
182 if (m_dispatchList.empty()) { return; }
183
184 for (IDispatchable* dispatchable : m_dispatchList) {
185 dispatchable->dispatch();
186 }
187}
188
189dbus_bool_t CDBusDispatcher::dbusAddWatch(DBusWatch* watch)
190{
191 if (dbus_watch_get_enabled(watch) == FALSE) { return true; }
192
193 int fd = dbus_watch_get_unix_fd(watch);
194 m_watchers.emplace(fd, our_make_unique<WatchHandler>(m_eventBase.get(), watch));
195 return true;
196}
197
198void CDBusDispatcher::dbusRemoveWatch(DBusWatch* watch)
199{
200 for (auto it = m_watchers.begin(); it != m_watchers.end();) {
201 if (it->second->getWatch() == watch) {
202 it = m_watchers.erase(it);
203 } else {
204 ++it;
205 }
206 }
207}
208
209void CDBusDispatcher::dbusWatchToggled(DBusWatch* watch)
210{
211 if (dbus_watch_get_enabled(watch) == TRUE) {
212 dbusAddWatch(watch);
213 } else {
214 dbusRemoveWatch(watch);
215 }
216}
217
218dbus_bool_t CDBusDispatcher::dbusAddTimeout(DBusTimeout* timeout)
219{
220 if (dbus_timeout_get_enabled(timeout) == FALSE) { return TRUE; }
221 m_timeouts.emplace_back(new TimeoutHandler(m_eventBase.get(), timeout));
222 return true;
223}
224
225void CDBusDispatcher::dbusRemoveTimeout(DBusTimeout* timeout)
226{
227 auto predicate = [timeout](const std::unique_ptr<TimeoutHandler>& ptr) {
228 return ptr->getTimeout() == timeout;
229 };
230
231 m_timeouts.erase(std::remove_if(m_timeouts.begin(), m_timeouts.end(), predicate), m_timeouts.end());
232}
233
234void CDBusDispatcher::dbusTimeoutToggled(DBusTimeout* timeout)
235{
236 if (dbus_timeout_get_enabled(timeout) == TRUE)
237 dbusAddTimeout(timeout);
238 else
239 dbusRemoveTimeout(timeout);
240}
241
242} // namespace flightgear::swift
void remove(IDispatchable *dispatchable)
Remove dispatchable object.
void waitAndRun()
Waits for events to be dispatched and handles them.
void add(IDispatchable *dispatchable)
Add dispatchable object.
void runOnce()
Dispatches ready handlers and returns without waiting.
Dispatchable Interface.
TimeoutHandler(event_base *base, DBusTimeout *timeout)
Constructor.
const DBusTimeout * getTimeout() const
Get DBus timeout.
Timer(event_base *base, const timeval &timeout, const std::function< void()> &func)
Constructor.
WatchHandler(event_base *base, DBusWatch *watch)
Constructor.
const DBusWatch * getWatch() const
Get DBus watch.
DBusWatch * getWatch()
Get DBus watch.
naCFunction func
Functor struct deleteing an event.
void operator()(event *obj) const
Delete functor.