21
21
#include <stdexcept>
22
22
#include <algorithm>
23
#include <condition_variable>
24
25
#include <boost/throw_exception.hpp>
30
class AlarmImpl : public mir::time::Alarm
34
GMainContext* main_context,
35
std::shared_ptr<mir::time::Clock> const& clock,
36
std::function<void()> const& callback)
37
: main_context{main_context},
40
state_{State::cancelled}
44
bool cancel() override
46
std::lock_guard<std::mutex> lock{alarm_mutex};
48
gsource = mir::detail::GSourceHandle{};
49
state_ = State::cancelled;
53
State state() const override
55
std::lock_guard<std::mutex> lock{alarm_mutex};
59
bool reschedule_in(std::chrono::milliseconds delay) override
61
return reschedule_for(clock->now() + delay);
64
bool reschedule_for(mir::time::Timestamp time_point) override
66
std::lock_guard<std::mutex> lock{alarm_mutex};
68
state_ = State::pending;
69
gsource = mir::detail::add_timer_gsource(
72
[&] { state_ = State::triggered; callback(); },
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;
84
mir::detail::GSourceHandle gsource;
26
89
mir::detail::GMainContextHandle::GMainContextHandle()
27
90
: main_context{g_main_context_new()}
127
194
auto const iter = std::find(do_not_process.begin(), do_not_process.end(), owner);
128
195
return iter == do_not_process.end();
198
std::unique_ptr<mir::time::Alarm> mir::GLibMainLoop::notify_in(
199
std::chrono::milliseconds delay,
200
std::function<void()> callback)
202
auto alarm = create_alarm(callback);
204
alarm->reschedule_in(delay);
209
std::unique_ptr<mir::time::Alarm> mir::GLibMainLoop::notify_at(
210
mir::time::Timestamp t,
211
std::function<void()> callback)
213
auto alarm = create_alarm(callback);
215
alarm->reschedule_for(t);
220
std::unique_ptr<mir::time::Alarm> mir::GLibMainLoop::create_alarm(
221
std::function<void()> callback)
223
return std::unique_ptr<mir::time::Alarm>{
224
new AlarmImpl(main_context, clock, callback)};
227
void mir::GLibMainLoop::reprocess_all_sources()
229
std::condition_variable reprocessed_cv;
230
std::mutex reprocessed_mutex;
231
bool reprocessed = false;
233
// Schedule setting the before_iteration_hook as an
234
// idle source to ensure there is no concurrent access
236
detail::add_idle_gsource(main_context, G_PRIORITY_HIGH,
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 =
248
detail::add_idle_gsource(main_context, G_PRIORITY_LOW,
251
std::lock_guard<std::mutex> lock{reprocessed_mutex};
253
reprocessed_cv.notify_all();
256
before_iteration_hook = []{};
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);
265
std::unique_lock<std::mutex> reprocessed_lock{reprocessed_mutex};
266
reprocessed_cv.wait(reprocessed_lock, [&] { return reprocessed == true; });