~vanvugt/mir/pageflip-timings

« back to all changes in this revision

Viewing changes to src/server/glib_main_loop_sources.cpp

  • Committer: Tarmac
  • Author(s): Alexandros Frantzis
  • Date: 2014-11-10 21:41:12 UTC
  • mfrom: (2026.1.8 glib-main-loop-fd)
  • Revision ID: tarmac-20141110214112-8mryou6qc4gy3lld
server: Add fd support to GLibMainLoop.

Approved by Alan Griffiths, PS Jenkins bot, Alberto Aguirre.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 */
18
18
 
19
19
#include "mir/glib_main_loop_sources.h"
 
20
#include "mir/recursive_read_write_mutex.h"
20
21
 
21
22
#include <glib-unix.h>
 
23
#include <algorithm>
22
24
 
23
25
namespace md = mir::detail;
24
26
 
 
27
namespace
 
28
{
 
29
 
 
30
class GSourceRef
 
31
{
 
32
public:
 
33
    GSourceRef(GSource* gsource) : gsource{gsource} {}
 
34
    ~GSourceRef() { if (gsource) g_source_unref(gsource); }
 
35
    operator GSource*() const { return gsource; }
 
36
 
 
37
private:
 
38
    GSourceRef(GSourceRef const&) = delete;
 
39
    GSourceRef& operator=(GSourceRef const&) = delete;
 
40
 
 
41
    GSource* gsource;
 
42
};
 
43
 
 
44
}
 
45
 
25
46
/*****************
26
47
 * GSourceHandle *
27
48
 *****************/
28
49
 
29
 
md::GSourceHandle::GSourceHandle(GSource* gsource)
30
 
    : gsource{gsource}
 
50
md::GSourceHandle::GSourceHandle(
 
51
    GSource* gsource,
 
52
    std::function<void()> const& pre_destruction_hook)
 
53
    : gsource{gsource},
 
54
      pre_destruction_hook{pre_destruction_hook}
31
55
{
32
56
}
33
57
 
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)}
36
61
{
37
62
    other.gsource = nullptr;
 
63
    other.pre_destruction_hook = []{};
38
64
}
39
65
 
40
66
md::GSourceHandle::~GSourceHandle()
41
67
{
42
68
    if (gsource)
 
69
    {
 
70
        pre_destruction_hook();
 
71
        g_source_destroy(gsource);
43
72
        g_source_unref(gsource);
 
73
    }
44
74
}
45
75
 
46
 
void md::GSourceHandle::attach(GMainContext* main_context) const
 
76
md::GSourceHandle::operator GSource*() const
47
77
{
48
 
    g_source_attach(gsource, main_context);
 
78
    return gsource;
49
79
}
50
80
 
51
81
/******************
52
82
 * make_*_gsource *
53
83
 ******************/
54
84
 
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)
56
87
{
57
88
    struct IdleContext
58
89
    {
65
96
        std::function<void()> const callback;
66
97
    };
67
98
 
68
 
    auto const gsource = g_idle_source_new();
 
99
    GSourceRef gsource{g_idle_source_new()};
 
100
 
69
101
    g_source_set_priority(gsource, priority);
70
102
    g_source_set_callback(
71
103
        gsource,
73
105
        new IdleContext{callback},
74
106
        reinterpret_cast<GDestroyNotify>(&IdleContext::static_destroy));
75
107
 
76
 
    return GSourceHandle{gsource};
 
108
    g_source_attach(gsource, main_context);
77
109
}
78
110
 
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)
81
114
{
82
115
    struct SignalContext
91
124
        int sig;
92
125
    };
93
126
 
94
 
    auto const gsource = g_unix_signal_source_new(sig);
 
127
    GSourceRef gsource{g_unix_signal_source_new(sig)};
 
128
 
95
129
    g_source_set_callback(
96
130
        gsource,
97
131
        reinterpret_cast<GSourceFunc>(&SignalContext::static_call),
98
132
        new SignalContext{callback, sig},
99
133
        reinterpret_cast<GDestroyNotify>(&SignalContext::static_destroy));
100
134
 
101
 
    return GSourceHandle{gsource};
 
135
    g_source_attach(gsource, main_context);
 
136
}
 
137
 
 
138
/*************
 
139
 * FdSources *
 
140
 *************/
 
141
 
 
142
struct md::FdSources::FdContext
 
143
{
 
144
    FdContext(std::function<void(int)> const& handler)
 
145
        : handler{handler}, enabled{true}
 
146
    {
 
147
    }
 
148
 
 
149
    void disable_callback()
 
150
    {
 
151
        RecursiveWriteLock lock{mutex};
 
152
        enabled = false;
 
153
    }
 
154
 
 
155
    static gboolean static_call(int fd, GIOCondition, FdContext* ctx)
 
156
    {
 
157
        RecursiveReadLock lock{ctx->mutex};
 
158
 
 
159
        if (ctx->enabled)
 
160
            ctx->handler(fd);
 
161
 
 
162
        return G_SOURCE_CONTINUE;
 
163
    }
 
164
 
 
165
    static void static_destroy(FdContext* ctx)
 
166
    {
 
167
        delete ctx;
 
168
    }
 
169
 
 
170
private:
 
171
    std::function<void(int)> handler;
 
172
    bool enabled;
 
173
    mir::RecursiveReadWriteMutex mutex;
 
174
};
 
175
 
 
176
struct md::FdSources::FdSource
 
177
{
 
178
    GSourceHandle gsource;
 
179
    void const* const owner;
 
180
};
 
181
 
 
182
md::FdSources::FdSources(GMainContext* main_context)
 
183
    : main_context{main_context}
 
184
{
 
185
}
 
186
 
 
187
md::FdSources::~FdSources() = default;
 
188
 
 
189
void md::FdSources::add(
 
190
    int fd, void const* owner, std::function<void(int)> const& handler)
 
191
{
 
192
    auto const fd_context = new FdContext{handler};
 
193
 
 
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
 
198
    // destruction.
 
199
    GSourceHandle gsource{
 
200
        g_unix_fd_source_new(fd, G_IO_IN),
 
201
        [=] { fd_context->disable_callback(); }};
 
202
 
 
203
    g_source_set_callback(
 
204
        gsource,
 
205
        reinterpret_cast<GSourceFunc>(&FdContext::static_call),
 
206
        fd_context,
 
207
        reinterpret_cast<GDestroyNotify>(&FdContext::static_destroy));
 
208
 
 
209
    std::lock_guard<std::mutex> lock{sources_mutex};
 
210
 
 
211
    sources.emplace_back(new FdSource{std::move(gsource), owner});
 
212
    g_source_attach(sources.back()->gsource, main_context);
 
213
}
 
214
 
 
215
void md::FdSources::remove_all_owned_by(void const* owner)
 
216
{
 
217
    std::lock_guard<std::mutex> lock{sources_mutex};
 
218
 
 
219
    auto const new_end = std::remove_if(
 
220
        sources.begin(), sources.end(),
 
221
        [&] (std::unique_ptr<FdSource> const& fd_source)
 
222
        {
 
223
            return fd_source->owner == owner;
 
224
        });
 
225
 
 
226
    sources.erase(new_end, sources.end());
102
227
}