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
=== modified file 'src/clock-live.cpp'
--- src/clock-live.cpp 2014-09-16 19:55:30 +0000
+++ src/clock-live.cpp 2015-02-13 20:32:42 +0000
@@ -20,6 +20,15 @@
20#include <datetime/clock.h>20#include <datetime/clock.h>
21#include <datetime/timezone.h>21#include <datetime/timezone.h>
2222
23#include <glib-unix.h> // g_unix_fd_add()
24
25#include <sys/timerfd.h>
26#include <unistd.h> // close()
27
28#ifndef TFD_TIMER_CANCEL_ON_SET
29 #define TFD_TIMER_CANCEL_ON_SET (1 << 1)
30#endif
31
23namespace unity {32namespace unity {
24namespace indicator {33namespace indicator {
25namespace datetime {34namespace datetime {
@@ -28,33 +37,6 @@
28****37****
29***/38***/
3039
31namespace
32{
33
34void clearTimer(guint& tag)
35{
36 if (tag)
37 {
38 g_source_remove(tag);
39 tag = 0;
40 }
41}
42
43guint calculate_milliseconds_until_next_minute(const DateTime& now)
44{
45 auto next = g_date_time_add_minutes(now.get(), 1);
46 auto start_of_next = g_date_time_add_seconds (next, -g_date_time_get_seconds(next));
47 const auto interval_usec = g_date_time_difference(start_of_next, now.get());
48 const guint interval_msec = (interval_usec + 999) / 1000;
49 g_date_time_unref(start_of_next);
50 g_date_time_unref(next);
51 g_assert (interval_msec <= 60000);
52 return interval_msec;
53}
54
55} // unnamed namespace
56
57
58class LiveClock::Impl40class LiveClock::Impl
59{41{
60public:42public:
@@ -70,12 +52,31 @@
70 setter(m_timezone->timezone.get());52 setter(m_timezone->timezone.get());
71 }53 }
7254
73 restart_minute_timer();55 m_timerfd = timerfd_create(CLOCK_REALTIME, 0);
56 if (m_timerfd == -1)
57 {
58 g_warning("unable to create realtime timer: %s", g_strerror(errno));
59 }
60 else
61 {
62 reset_timer();
63
64 m_timerfd_tag = g_unix_fd_add(m_timerfd,
65 (GIOCondition)(G_IO_IN|G_IO_HUP|G_IO_ERR),
66 on_timerfd_cond,
67 this);
68 }
69
70 refresh();
74 }71 }
7572
76 ~Impl()73 ~Impl()
77 {74 {
78 clearTimer(m_timer);75 if (m_timerfd_tag != 0)
76 g_source_remove(m_timerfd_tag);
77
78 if (m_timerfd != -1)
79 close(m_timerfd);
7980
80 g_clear_pointer(&m_gtimezone, g_time_zone_unref);81 g_clear_pointer(&m_gtimezone, g_time_zone_unref);
81 }82 }
@@ -92,6 +93,61 @@
9293
93private:94private:
9495
96 void reset_timer()
97 {
98 struct itimerspec timerval;
99 // set args to fire at the beginning of the next minute...
100 int flags = TFD_TIMER_ABSTIME;
101 auto now = g_date_time_new_now(m_gtimezone);
102 auto next = g_date_time_add_minutes(now, 1);
103 auto start_of_next = g_date_time_add_seconds(next, -g_date_time_get_seconds(next));
104 timerval.it_value.tv_sec = g_date_time_to_unix(start_of_next);
105 timerval.it_value.tv_nsec = 0;
106 g_date_time_unref(start_of_next);
107 g_date_time_unref(next);
108 g_date_time_unref(now);
109 // ...and also to fire at the beginning of every subsequent minute...
110 timerval.it_interval.tv_sec = 60;
111 timerval.it_interval.tv_nsec = 0;
112 // ...and also to fire if someone changes the time
113 // manually (eg toggling from manual<->ntp)
114 flags |= TFD_TIMER_CANCEL_ON_SET;
115
116 if (timerfd_settime(m_timerfd, flags, &timerval, NULL) == -1)
117 g_error("timerfd_settime failed: %s", g_strerror(errno));
118 }
119
120 static gboolean on_timerfd_cond (gint fd, GIOCondition cond, gpointer gself)
121 {
122 auto self = static_cast<Impl*>(gself);
123
124 int n_bytes = 0;
125 uint64_t n_interrupts = 0;
126 if (cond & G_IO_IN)
127 n_bytes = read(fd, &n_interrupts, sizeof(uint64_t));
128
129 if ((n_interrupts==0) || (n_bytes!=sizeof(uint64_t)))
130 {
131 auto now = g_date_time_new_now(self->m_gtimezone);
132 auto now_str = g_date_time_format(now, "%F %T");
133 g_message("%s triggered at %s.%06d by GIOCondition %d, read %zd bytes, found %zu interrupts",
134 G_STRFUNC, now_str, g_date_time_get_microsecond(now),
135 (int)cond, n_bytes, n_interrupts);
136 g_free(now_str);
137 g_date_time_unref(now);
138
139 // reset the timer in case someone changed the system clock
140 self->reset_timer();
141 }
142
143 self->refresh();
144 return G_SOURCE_CONTINUE;
145 }
146
147 /***
148 ****
149 ***/
150
95 void setTimezone(const std::string& str)151 void setTimezone(const std::string& str)
96 {152 {
97 g_clear_pointer(&m_gtimezone, g_time_zone_unref);153 g_clear_pointer(&m_gtimezone, g_time_zone_unref);
@@ -103,33 +159,17 @@
103 ****159 ****
104 ***/160 ***/
105161
106 void restart_minute_timer()162 void refresh()
107 {163 {
108 clearTimer(m_timer);164 const auto now = localtime();
109165
110 // maybe emit change signals166 // maybe emit change signals
111 const auto now = localtime();
112 if (!DateTime::is_same_minute(m_prev_datetime, now))167 if (!DateTime::is_same_minute(m_prev_datetime, now))
113 m_owner.minute_changed();168 m_owner.minute_changed();
114 if (!DateTime::is_same_day(m_prev_datetime, now))169 if (!DateTime::is_same_day(m_prev_datetime, now))
115 m_owner.date_changed();170 m_owner.date_changed();
116171
117 // queue up a timer to fire at the next minute
118 m_prev_datetime = now;172 m_prev_datetime = now;
119 auto interval_msec = calculate_milliseconds_until_next_minute(now);
120 interval_msec += 50; // add a small margin to ensure the callback
121 // fires /after/ next is reached
122 m_timer = g_timeout_add_full(G_PRIORITY_HIGH,
123 interval_msec,
124 on_minute_timer_reached,
125 this,
126 nullptr);
127 }
128
129 static gboolean on_minute_timer_reached(gpointer gself)
130 {
131 static_cast<LiveClock::Impl*>(gself)->restart_minute_timer();
132 return G_SOURCE_REMOVE;
133 }173 }
134174
135protected:175protected:
@@ -139,7 +179,8 @@
139 std::shared_ptr<const Timezone> m_timezone;179 std::shared_ptr<const Timezone> m_timezone;
140180
141 DateTime m_prev_datetime;181 DateTime m_prev_datetime;
142 unsigned int m_timer = 0;182 int m_timerfd = -1;
183 guint m_timerfd_tag = 0;
143};184};
144185
145LiveClock::LiveClock(const std::shared_ptr<const Timezone>& timezone_):186LiveClock::LiveClock(const std::shared_ptr<const Timezone>& timezone_):
146187
=== modified file 'tests/manual'
--- tests/manual 2015-01-21 21:33:53 +0000
+++ tests/manual 2015-02-13 20:32:42 +0000
@@ -137,6 +137,12 @@
137 <dd>The calendar event notification should play a sound.</dd>137 <dd>The calendar event notification should play a sound.</dd>
138</dl>138</dl>
139139
140Test-case indicator-datetime/manual-time
141<dl>
142 <dt>In System Settings > Time & Date, manually change the time to an arbitrary time.</dt>
143 <dd>The indicator's timestamp should change right after the time manual time is set.</dd>
144</dl>
145
140<strong>146<strong>
141 If all actions produce the expected results listed, please <a href="results#add_result">submit</a> a 'passed' result.147 If all actions produce the expected results listed, please <a href="results#add_result">submit</a> a 'passed' result.
142 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>.148 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