19
19
#include "mir/glib_main_loop_sources.h"
20
#include "mir/recursive_read_write_mutex.h"
21
22
#include <glib-unix.h>
23
25
namespace md = mir::detail;
33
GSourceRef(GSource* gsource) : gsource{gsource} {}
34
~GSourceRef() { if (gsource) g_source_unref(gsource); }
35
operator GSource*() const { return gsource; }
38
GSourceRef(GSourceRef const&) = delete;
39
GSourceRef& operator=(GSourceRef const&) = delete;
29
md::GSourceHandle::GSourceHandle(GSource* gsource)
50
md::GSourceHandle::GSourceHandle(
52
std::function<void()> const& pre_destruction_hook)
54
pre_destruction_hook{pre_destruction_hook}
34
md::GSourceHandle::GSourceHandle(md::GSourceHandle&& other)
35
: gsource{other.gsource}
58
md::GSourceHandle::GSourceHandle(GSourceHandle&& other)
59
: gsource{std::move(other.gsource)},
60
pre_destruction_hook{std::move(other.pre_destruction_hook)}
37
62
other.gsource = nullptr;
63
other.pre_destruction_hook = []{};
40
66
md::GSourceHandle::~GSourceHandle()
70
pre_destruction_hook();
71
g_source_destroy(gsource);
43
72
g_source_unref(gsource);
46
void md::GSourceHandle::attach(GMainContext* main_context) const
76
md::GSourceHandle::operator GSource*() const
48
g_source_attach(gsource, main_context);
51
81
/******************
53
83
******************/
55
md::GSourceHandle md::make_idle_gsource(int priority, std::function<void()> const& callback)
85
void md::add_idle_gsource(
86
GMainContext* main_context, int priority, std::function<void()> const& callback)
73
105
new IdleContext{callback},
74
106
reinterpret_cast<GDestroyNotify>(&IdleContext::static_destroy));
76
return GSourceHandle{gsource};
108
g_source_attach(gsource, main_context);
79
md::GSourceHandle md::make_signal_gsource(
111
void md::add_signal_gsource(
112
GMainContext* main_context,
80
113
int sig, std::function<void(int)> const& callback)
82
115
struct SignalContext
94
auto const gsource = g_unix_signal_source_new(sig);
127
GSourceRef gsource{g_unix_signal_source_new(sig)};
95
129
g_source_set_callback(
97
131
reinterpret_cast<GSourceFunc>(&SignalContext::static_call),
98
132
new SignalContext{callback, sig},
99
133
reinterpret_cast<GDestroyNotify>(&SignalContext::static_destroy));
101
return GSourceHandle{gsource};
135
g_source_attach(gsource, main_context);
142
struct md::FdSources::FdContext
144
FdContext(std::function<void(int)> const& handler)
145
: handler{handler}, enabled{true}
149
void disable_callback()
151
RecursiveWriteLock lock{mutex};
155
static gboolean static_call(int fd, GIOCondition, FdContext* ctx)
157
RecursiveReadLock lock{ctx->mutex};
162
return G_SOURCE_CONTINUE;
165
static void static_destroy(FdContext* ctx)
171
std::function<void(int)> handler;
173
mir::RecursiveReadWriteMutex mutex;
176
struct md::FdSources::FdSource
178
GSourceHandle gsource;
179
void const* const owner;
182
md::FdSources::FdSources(GMainContext* main_context)
183
: main_context{main_context}
187
md::FdSources::~FdSources() = default;
189
void md::FdSources::add(
190
int fd, void const* owner, std::function<void(int)> const& handler)
192
auto const fd_context = new FdContext{handler};
194
// g_source_destroy() may be called while the source is about to be
195
// dispatched, so there is no guarantee that after g_source_destroy()
196
// returns any associated handlers won't be called. Since we want a
197
// stronger guarantee we need to disable the callback manually before
199
GSourceHandle gsource{
200
g_unix_fd_source_new(fd, G_IO_IN),
201
[=] { fd_context->disable_callback(); }};
203
g_source_set_callback(
205
reinterpret_cast<GSourceFunc>(&FdContext::static_call),
207
reinterpret_cast<GDestroyNotify>(&FdContext::static_destroy));
209
std::lock_guard<std::mutex> lock{sources_mutex};
211
sources.emplace_back(new FdSource{std::move(gsource), owner});
212
g_source_attach(sources.back()->gsource, main_context);
215
void md::FdSources::remove_all_owned_by(void const* owner)
217
std::lock_guard<std::mutex> lock{sources_mutex};
219
auto const new_end = std::remove_if(
220
sources.begin(), sources.end(),
221
[&] (std::unique_ptr<FdSource> const& fd_source)
223
return fd_source->owner == owner;
226
sources.erase(new_end, sources.end());