Merge lp:~charlesk/indicator-datetime/lp-1405806-improve-clock-change-detection-rtm-14.09 into lp:indicator-datetime/rtm-14.09

Proposed by Charles Kerr
Status: Merged
Approved by: Ted Gould
Approved revision: 395
Merged at revision: 395
Proposed branch: lp:~charlesk/indicator-datetime/lp-1405806-improve-clock-change-detection-rtm-14.09
Merge into: lp:indicator-datetime/rtm-14.09
Diff against target: 212 lines (+95/-48)
2 files modified
src/clock-live.cpp (+89/-48)
tests/manual (+6/-0)
To merge this branch: bzr merge lp:~charlesk/indicator-datetime/lp-1405806-improve-clock-change-detection-rtm-14.09
Reviewer Review Type Date Requested Status
Ted Gould (community) Approve
Review via email: mp+249719@code.launchpad.net

Commit message

change the WallClock to detect time changes from TFD_TIMER_CANCEL_ON_SET, e.g. when ntp<-->manual is toggled

Description of the change

To post a comment you must log in.
Revision history for this message
Ted Gould (ted) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/clock-live.cpp'
2--- src/clock-live.cpp 2014-09-16 19:55:30 +0000
3+++ src/clock-live.cpp 2015-02-13 20:32:42 +0000
4@@ -20,6 +20,15 @@
5 #include <datetime/clock.h>
6 #include <datetime/timezone.h>
7
8+#include <glib-unix.h> // g_unix_fd_add()
9+
10+#include <sys/timerfd.h>
11+#include <unistd.h> // close()
12+
13+#ifndef TFD_TIMER_CANCEL_ON_SET
14+ #define TFD_TIMER_CANCEL_ON_SET (1 << 1)
15+#endif
16+
17 namespace unity {
18 namespace indicator {
19 namespace datetime {
20@@ -28,33 +37,6 @@
21 ****
22 ***/
23
24-namespace
25-{
26-
27-void clearTimer(guint& tag)
28-{
29- if (tag)
30- {
31- g_source_remove(tag);
32- tag = 0;
33- }
34-}
35-
36-guint calculate_milliseconds_until_next_minute(const DateTime& now)
37-{
38- auto next = g_date_time_add_minutes(now.get(), 1);
39- auto start_of_next = g_date_time_add_seconds (next, -g_date_time_get_seconds(next));
40- const auto interval_usec = g_date_time_difference(start_of_next, now.get());
41- const guint interval_msec = (interval_usec + 999) / 1000;
42- g_date_time_unref(start_of_next);
43- g_date_time_unref(next);
44- g_assert (interval_msec <= 60000);
45- return interval_msec;
46-}
47-
48-} // unnamed namespace
49-
50-
51 class LiveClock::Impl
52 {
53 public:
54@@ -70,12 +52,31 @@
55 setter(m_timezone->timezone.get());
56 }
57
58- restart_minute_timer();
59+ m_timerfd = timerfd_create(CLOCK_REALTIME, 0);
60+ if (m_timerfd == -1)
61+ {
62+ g_warning("unable to create realtime timer: %s", g_strerror(errno));
63+ }
64+ else
65+ {
66+ reset_timer();
67+
68+ m_timerfd_tag = g_unix_fd_add(m_timerfd,
69+ (GIOCondition)(G_IO_IN|G_IO_HUP|G_IO_ERR),
70+ on_timerfd_cond,
71+ this);
72+ }
73+
74+ refresh();
75 }
76
77 ~Impl()
78 {
79- clearTimer(m_timer);
80+ if (m_timerfd_tag != 0)
81+ g_source_remove(m_timerfd_tag);
82+
83+ if (m_timerfd != -1)
84+ close(m_timerfd);
85
86 g_clear_pointer(&m_gtimezone, g_time_zone_unref);
87 }
88@@ -92,6 +93,61 @@
89
90 private:
91
92+ void reset_timer()
93+ {
94+ struct itimerspec timerval;
95+ // set args to fire at the beginning of the next minute...
96+ int flags = TFD_TIMER_ABSTIME;
97+ auto now = g_date_time_new_now(m_gtimezone);
98+ auto next = g_date_time_add_minutes(now, 1);
99+ auto start_of_next = g_date_time_add_seconds(next, -g_date_time_get_seconds(next));
100+ timerval.it_value.tv_sec = g_date_time_to_unix(start_of_next);
101+ timerval.it_value.tv_nsec = 0;
102+ g_date_time_unref(start_of_next);
103+ g_date_time_unref(next);
104+ g_date_time_unref(now);
105+ // ...and also to fire at the beginning of every subsequent minute...
106+ timerval.it_interval.tv_sec = 60;
107+ timerval.it_interval.tv_nsec = 0;
108+ // ...and also to fire if someone changes the time
109+ // manually (eg toggling from manual<->ntp)
110+ flags |= TFD_TIMER_CANCEL_ON_SET;
111+
112+ if (timerfd_settime(m_timerfd, flags, &timerval, NULL) == -1)
113+ g_error("timerfd_settime failed: %s", g_strerror(errno));
114+ }
115+
116+ static gboolean on_timerfd_cond (gint fd, GIOCondition cond, gpointer gself)
117+ {
118+ auto self = static_cast<Impl*>(gself);
119+
120+ int n_bytes = 0;
121+ uint64_t n_interrupts = 0;
122+ if (cond & G_IO_IN)
123+ n_bytes = read(fd, &n_interrupts, sizeof(uint64_t));
124+
125+ if ((n_interrupts==0) || (n_bytes!=sizeof(uint64_t)))
126+ {
127+ auto now = g_date_time_new_now(self->m_gtimezone);
128+ auto now_str = g_date_time_format(now, "%F %T");
129+ g_message("%s triggered at %s.%06d by GIOCondition %d, read %zd bytes, found %zu interrupts",
130+ G_STRFUNC, now_str, g_date_time_get_microsecond(now),
131+ (int)cond, n_bytes, n_interrupts);
132+ g_free(now_str);
133+ g_date_time_unref(now);
134+
135+ // reset the timer in case someone changed the system clock
136+ self->reset_timer();
137+ }
138+
139+ self->refresh();
140+ return G_SOURCE_CONTINUE;
141+ }
142+
143+ /***
144+ ****
145+ ***/
146+
147 void setTimezone(const std::string& str)
148 {
149 g_clear_pointer(&m_gtimezone, g_time_zone_unref);
150@@ -103,33 +159,17 @@
151 ****
152 ***/
153
154- void restart_minute_timer()
155+ void refresh()
156 {
157- clearTimer(m_timer);
158+ const auto now = localtime();
159
160 // maybe emit change signals
161- const auto now = localtime();
162 if (!DateTime::is_same_minute(m_prev_datetime, now))
163 m_owner.minute_changed();
164 if (!DateTime::is_same_day(m_prev_datetime, now))
165 m_owner.date_changed();
166
167- // queue up a timer to fire at the next minute
168 m_prev_datetime = now;
169- auto interval_msec = calculate_milliseconds_until_next_minute(now);
170- interval_msec += 50; // add a small margin to ensure the callback
171- // fires /after/ next is reached
172- m_timer = g_timeout_add_full(G_PRIORITY_HIGH,
173- interval_msec,
174- on_minute_timer_reached,
175- this,
176- nullptr);
177- }
178-
179- static gboolean on_minute_timer_reached(gpointer gself)
180- {
181- static_cast<LiveClock::Impl*>(gself)->restart_minute_timer();
182- return G_SOURCE_REMOVE;
183 }
184
185 protected:
186@@ -139,7 +179,8 @@
187 std::shared_ptr<const Timezone> m_timezone;
188
189 DateTime m_prev_datetime;
190- unsigned int m_timer = 0;
191+ int m_timerfd = -1;
192+ guint m_timerfd_tag = 0;
193 };
194
195 LiveClock::LiveClock(const std::shared_ptr<const Timezone>& timezone_):
196
197=== modified file 'tests/manual'
198--- tests/manual 2015-01-21 21:33:53 +0000
199+++ tests/manual 2015-02-13 20:32:42 +0000
200@@ -137,6 +137,12 @@
201 <dd>The calendar event notification should play a sound.</dd>
202 </dl>
203
204+Test-case indicator-datetime/manual-time
205+<dl>
206+ <dt>In System Settings > Time & Date, manually change the time to an arbitrary time.</dt>
207+ <dd>The indicator's timestamp should change right after the time manual time is set.</dd>
208+</dl>
209+
210 <strong>
211 If all actions produce the expected results listed, please <a href="results#add_result">submit</a> a 'passed' result.
212 If an action fails, or produces an unexpected result, please <a href="results#add_result">submit</a> a 'failed' result and <a href="../../buginstructions">file a bug</a>. Please be sure to include the bug number when you <a href="results#add_result">submit</a> your result</strong>.

Subscribers

People subscribed via source and target branches