File hwclock-adjust-and-hctosys.diff of Package util-linux
From: Kurt Garloff <garloff@suse.de>
Subject: Allow to combine --adjust and --hctosys
Reference: bnc441106
Waiting for a clock tick twice when calling --adjust and --hctosys
is wasteful. Having to do it once is bad enough.
This patch allows combining the two options.
It does two additional things:
The busy wait loop for set_hardware_clock_exact() is replaced by a
version that does some usleep()ing to save CPU cycles. It's broken
out in a separate function.
It also uses the newly introduced usec granularity of set_system_clock()
to avoid the up to 1s inaccuracy in --preadjust.
[Patch 4/4]
Index: util-linux-ng-2.14.1/hwclock/hwclock.c
===================================================================
--- util-linux-ng-2.14.1.orig/hwclock/hwclock.c
+++ util-linux-ng-2.14.1/hwclock/hwclock.c
@@ -489,19 +489,13 @@ set_hardware_clock(const time_t newtime,
err = ur->set_hardware_clock(&new_broken_time);
}
}
+static int
+set_system_clock(const bool hclock_valid, const time_t newtime,
+ const bool testing, const int usec);
-
-static void
-set_hardware_clock_exact(const time_t sethwtime,
- const struct timeval refsystime,
- const bool universal,
- const bool testing) {
/*----------------------------------------------------------------------------
- Set the Hardware Clock to the time "sethwtime", in local time zone or UTC,
- according to "universal".
-
Wait for a fraction of a second so that "sethwtime" is the value of
the Hardware Clock as of system time "refsystime", which is in the past.
For example, if "sethwtime" is 14:03:05 and "refsystime" is 12:10:04.5
and the current system time is 12:10:06.0: Wait .5 seconds (to make
@@ -514,11 +508,16 @@ set_hardware_clock_exact(const time_t se
This function ought to be able to accept set times as fractional times.
Idea for future enhancement.
-----------------------------------------------------------------------------*/
-
+static time_t
+time_busy_wait(const time_t sethwtime,
+ const struct timeval refsystime,
+ float delta)
+{
time_t newhwtime;
struct timeval beginsystime, nowsystime;
+ float towait;
time_resync:
gettimeofday(&beginsystime, NULL);
newhwtime = sethwtime + (int) time_diff(beginsystime, refsystime) + 1;
@@ -538,15 +537,35 @@ set_hardware_clock_exact(const time_t se
gettimeofday(&nowsystime, NULL);
tdiff = time_diff(nowsystime, beginsystime);
if (tdiff < 0)
goto time_resync; /* probably time was reset */
- } while (time_diff(nowsystime, refsystime) - 0.5 < newhwtime - sethwtime);
+ towait = newhwtime - sethwtime + delta - time_diff(nowsystime, refsystime);
+ if (towait > 0.08) {
+ usleep(1000000*(towait-0.08));
+ towait = 0.08;
+ }
+ } while (towait > 0);
+ return newhwtime;
+}
+static void
+set_hardware_clock_exact(const time_t sethwtime,
+ const struct timeval refsystime,
+ const bool universal,
+ const bool testing,
+ const bool hctosys) {
+/*----------------------------------------------------------------------------
+ Set the Hardware Clock to the time "sethwtime", in local time zone or UTC,
+ according to "universal".
+-----------------------------------------------------------------------------*/
+
+ time_t newhwtime = time_busy_wait(sethwtime, refsystime, 0.5);
+ if (hctosys)
+ set_system_clock(TRUE, newhwtime, testing, 500000);
set_hardware_clock(newhwtime, universal, testing);
}
-
static void
display_time(const bool hclock_valid, const time_t systime,
const double sync_duration) {
/*----------------------------------------------------------------------------
@@ -672,9 +691,9 @@ interpret_date_string(const char *date_o
static int
set_system_clock(const bool hclock_valid, const time_t newtime,
- const bool testing) {
+ const bool testing, const int usec) {
/*----------------------------------------------------------------------------
Set the System Clock to time 'newtime'.
Also set the kernel time zone value to the value indicated by the
@@ -700,9 +719,9 @@ set_system_clock(const bool hclock_valid
int minuteswest;
int rc;
tv.tv_sec = newtime;
- tv.tv_usec = 0;
+ tv.tv_usec = usec;
broken = localtime(&newtime);
#ifdef HAVE_TM_GMTOFF
minuteswest = -broken->tm_gmtoff/60; /* GNU extension */
@@ -936,9 +955,10 @@ save_adjtime(const struct adjtime adjtim
static void
do_adjustment(struct adjtime *adjtime_p,
const bool hclock_valid, const time_t hclocktime,
const struct timeval read_time,
- const bool universal, const bool testing) {
+ const bool universal, const bool testing,
+ const bool hctosys) {
/*---------------------------------------------------------------------------
Do the adjustment requested, by 1) setting the Hardware Clock (if
necessary), and 2) updating the last-adjusted time in the adjtime
structure.
@@ -991,9 +1011,9 @@ do_adjustment(struct adjtime *adjtime_p,
&adjustment, &retro);
if (adjustment > 0 || adjustment < -1) {
set_hardware_clock_exact(hclocktime + adjustment,
time_inc(read_time, -retro),
- universal, testing);
+ universal, testing, hctosys);
adjtime_p->last_adj_time = hclocktime + adjustment;
adjtime_p->not_adjusted = 0;
adjtime_p->dirty = TRUE;
} else
@@ -1047,8 +1067,9 @@ manipulate_clock(const bool show, const
struct adjtime adjtime;
/* Contents of the adjtime file, or what they should be. */
int rc; /* local return code */
bool no_auth; /* User lacks necessary authorization to access the clock */
+ int usec = 0;
no_auth = ur->get_permissions();
if (no_auth)
return EX_NOPERM;
@@ -1104,27 +1125,23 @@ manipulate_clock(const bool show, const
adjtime.not_adjusted,
hclocktime,
&adjustment, &retro);
hclocktime += adjustment;
- /* We can safely ignore retro here as it's a positive value,
- * thus by ignoring it we at worst set the time a bit more
- * backwards than we would ideally, which is safe, as a subsequent
- * exact setting will only cause a jump forward which is harmless.
- * We could do: usleep((1-retro)*1000000); hclocktime += 1; */
+ usec = 1000000*retro;
}
if (show) {
display_time(hclock_valid, hclocktime,
time_diff(read_time, startup_time));
} else if (set) {
set_hardware_clock_exact(set_time, startup_time,
- universal, testing);
+ universal, testing, FALSE);
if (!noadjfile)
adjust_drift_factor(&adjtime, set_time, hclock_valid, hclocktime,
time_diff(read_time, startup_time));
} else if (adjust) {
do_adjustment(&adjtime, hclock_valid, hclocktime,
- read_time, universal, testing);
+ read_time, universal, testing, hctosys);
} else if (systohc) {
struct timeval nowtime, reftime;
/* We can only set_hardware_clock_exact to a whole seconds
time, so we set it with reference to the most recent
@@ -1134,14 +1151,14 @@ manipulate_clock(const bool show, const
reftime.tv_sec = nowtime.tv_sec;
reftime.tv_usec = 0;
set_hardware_clock_exact((time_t) reftime.tv_sec, reftime,
- universal, testing);
+ universal, testing, FALSE);
if (!noadjfile)
adjust_drift_factor(&adjtime, (time_t) reftime.tv_sec, hclock_valid,
hclocktime, (double) read_time.tv_usec / 1E6);
} else if (hctosys) {
- rc = set_system_clock(hclock_valid, hclocktime, testing);
+ rc = set_system_clock(hclock_valid, hclocktime, testing, usec);
if (rc) {
printf(_("Unable to set system clock.\n"));
return rc;
}
@@ -1479,9 +1496,9 @@ main(int argc, char **argv) {
"You supplied %d.\n"),
MYNAME, argc);
}
- if (show + set + systohc + hctosys + adjust + getepoch + setepoch > 1){
+ if (show + set + systohc + hctosys + getepoch + setepoch > 1){
fprintf(stderr, _("You have specified multiple functions.\n"
"You can only perform one function "
"at a time.\n"));
hwclock_exit(EX_USAGE);
Index: util-linux-ng-2.14.1/hwclock/hwclock.8
===================================================================
--- util-linux-ng-2.14.1.orig/hwclock/hwclock.8
+++ util-linux-ng-2.14.1/hwclock/hwclock.8
@@ -199,21 +199,17 @@ from not using this option. This option
(
.B \-s
). This option is often combined
.B \-\-preadjust
-and then followed by asynchronous calls with
-.B \-\-adjust
-and
-.B \-\-hctosys
+and then followed by an asynchronous call with
+.B \-\-adjust \-\-hctosys
.TP
.B \-\-preadjust
causes hwclock to use the drift information from adjfile when transferring
the hwclock time to the system time. Unlike
.B \-\-adjust
-it will not update the adjfile nor change the hwclock. The calculation does
-discard sub-second corrections and may result in a time that's up to 1s behind
-the real value.
+it will not update the adjfile nor change the hwclock.
.TP
.B \-\-rtc=filename
overrides the default /dev file name, which is