~vanvugt/mir/pageflip-timings

« back to all changes in this revision

Viewing changes to src/server/glib_main_loop.cpp

  • Committer: Tarmac
  • Author(s): Alexandros Frantzis
  • Date: 2014-11-12 20:20:56 UTC
  • mfrom: (2026.1.12 glib-main-loop-timer)
  • Revision ID: tarmac-20141112202056-n5qvrhn39jyn0by5
server: Add timer support to GLibMainLoop.

Approved by Kevin DuBois, Alan Griffiths, PS Jenkins bot.

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
 
21
21
#include <stdexcept>
22
22
#include <algorithm>
 
23
#include <condition_variable>
23
24
 
24
25
#include <boost/throw_exception.hpp>
25
26
 
 
27
namespace
 
28
{
 
29
 
 
30
class AlarmImpl : public mir::time::Alarm
 
31
{
 
32
public:
 
33
    AlarmImpl(
 
34
        GMainContext* main_context,
 
35
        std::shared_ptr<mir::time::Clock> const& clock,
 
36
        std::function<void()> const& callback)
 
37
        : main_context{main_context},
 
38
          clock{clock},
 
39
          callback{callback},
 
40
          state_{State::cancelled}
 
41
    {
 
42
    }
 
43
 
 
44
    bool cancel() override
 
45
    {
 
46
        std::lock_guard<std::mutex> lock{alarm_mutex};
 
47
 
 
48
        gsource = mir::detail::GSourceHandle{};
 
49
        state_ = State::cancelled;
 
50
        return true;
 
51
    }
 
52
 
 
53
    State state() const override
 
54
    {
 
55
        std::lock_guard<std::mutex> lock{alarm_mutex};
 
56
        return state_;
 
57
    }
 
58
 
 
59
    bool reschedule_in(std::chrono::milliseconds delay) override
 
60
    {
 
61
        return reschedule_for(clock->now() + delay);
 
62
    }
 
63
 
 
64
    bool reschedule_for(mir::time::Timestamp time_point) override
 
65
    {
 
66
        std::lock_guard<std::mutex> lock{alarm_mutex};
 
67
 
 
68
        state_ = State::pending;
 
69
        gsource = mir::detail::add_timer_gsource(
 
70
            main_context,
 
71
            clock,
 
72
            [&] { state_ = State::triggered; callback(); },
 
73
            time_point);
 
74
 
 
75
        return true;
 
76
    }
 
77
 
 
78
private:
 
79
    mutable std::mutex alarm_mutex;
 
80
    GMainContext* main_context;
 
81
    std::shared_ptr<mir::time::Clock> const clock;
 
82
    std::function<void()> const callback;
 
83
    State state_;
 
84
    mir::detail::GSourceHandle gsource;
 
85
};
 
86
 
 
87
}
 
88
 
26
89
mir::detail::GMainContextHandle::GMainContextHandle()
27
90
    : main_context{g_main_context_new()}
28
91
{
42
105
}
43
106
 
44
107
 
45
 
mir::GLibMainLoop::GLibMainLoop()
46
 
    : running{false},
47
 
      fd_sources{main_context}
 
108
mir::GLibMainLoop::GLibMainLoop(
 
109
    std::shared_ptr<time::Clock> const& clock)
 
110
    : clock{clock},
 
111
      running{false},
 
112
      fd_sources{main_context},
 
113
      before_iteration_hook{[]{}}
48
114
{
49
115
}
50
116
 
54
120
 
55
121
    while (running)
56
122
    {
 
123
        before_iteration_hook();
57
124
        g_main_context_iteration(main_context, TRUE);
58
125
    }
59
126
}
127
194
    auto const iter = std::find(do_not_process.begin(), do_not_process.end(), owner);
128
195
    return iter == do_not_process.end();
129
196
}
 
197
 
 
198
std::unique_ptr<mir::time::Alarm> mir::GLibMainLoop::notify_in(
 
199
    std::chrono::milliseconds delay,
 
200
    std::function<void()> callback)
 
201
{
 
202
    auto alarm = create_alarm(callback);
 
203
 
 
204
    alarm->reschedule_in(delay);
 
205
 
 
206
    return alarm;
 
207
}
 
208
 
 
209
std::unique_ptr<mir::time::Alarm> mir::GLibMainLoop::notify_at(
 
210
    mir::time::Timestamp t,
 
211
    std::function<void()> callback)
 
212
{
 
213
    auto alarm = create_alarm(callback);
 
214
 
 
215
    alarm->reschedule_for(t);
 
216
 
 
217
    return alarm;
 
218
}
 
219
 
 
220
std::unique_ptr<mir::time::Alarm> mir::GLibMainLoop::create_alarm(
 
221
    std::function<void()> callback)
 
222
{
 
223
    return std::unique_ptr<mir::time::Alarm>{
 
224
        new AlarmImpl(main_context, clock, callback)};
 
225
}
 
226
 
 
227
void mir::GLibMainLoop::reprocess_all_sources()
 
228
{
 
229
    std::condition_variable reprocessed_cv;
 
230
    std::mutex reprocessed_mutex;
 
231
    bool reprocessed = false;
 
232
 
 
233
    // Schedule setting the before_iteration_hook as an
 
234
    // idle source to ensure there is no concurrent access
 
235
    // to it.
 
236
    detail::add_idle_gsource(main_context, G_PRIORITY_HIGH,
 
237
        [&]
 
238
        {
 
239
            // GMainContexts process sources in order of decreasing priority.
 
240
            // Since all of our sources have priority higher than
 
241
            // G_PRIORITY_LOW, by adding a G_PRIORITY_LOW source, we can be
 
242
            // sure that when this source is processed all other sources will
 
243
            // have been processed before it. We add the source in the
 
244
            // before_iteration_hook to avoid premature notifications.
 
245
            before_iteration_hook =
 
246
                [&]
 
247
                {
 
248
                    detail::add_idle_gsource(main_context, G_PRIORITY_LOW,
 
249
                        [&]
 
250
                        {
 
251
                            std::lock_guard<std::mutex> lock{reprocessed_mutex};
 
252
                            reprocessed = true;
 
253
                            reprocessed_cv.notify_all();
 
254
                        });
 
255
 
 
256
                    before_iteration_hook = []{};
 
257
                };
 
258
 
 
259
            // Wake up the main loop to ensure that we eventually leave
 
260
            // g_main_context_iteration() and reprocess all sources after
 
261
            // having called the newly set before_iteration_hook.
 
262
            g_main_context_wakeup(main_context);
 
263
        });
 
264
 
 
265
    std::unique_lock<std::mutex> reprocessed_lock{reprocessed_mutex};
 
266
    reprocessed_cv.wait(reprocessed_lock, [&] { return reprocessed == true; });
 
267
}