diff options
-rw-r--r-- | Documentation/TODO | 2 | ||||
-rw-r--r-- | sys-utils/hwclock-cmos.c | 6 | ||||
-rw-r--r-- | sys-utils/hwclock-rtc.c | 6 | ||||
-rw-r--r-- | sys-utils/hwclock.8.in | 18 | ||||
-rw-r--r-- | sys-utils/hwclock.c | 76 | ||||
-rw-r--r-- | sys-utils/hwclock.h | 2 |
6 files changed, 102 insertions, 8 deletions
diff --git a/Documentation/TODO b/Documentation/TODO index 488cc0677..44c980581 100644 --- a/Documentation/TODO +++ b/Documentation/TODO @@ -65,8 +65,6 @@ hwlock - use /etc/adjtime as read-only for UTC/LOCAL information only - the /var/lib/hwclock/drift should be implemented backwardly compatible, it means use the file only if exists, otherwise follow /etc/adjtime - - add --delay-on-set <ms> to make possible to by-pass default 500ms delay on --set - https://marc.info/?l=util-linux-ng&m=146675599623002&w=2 bash completion --------------- diff --git a/sys-utils/hwclock-cmos.c b/sys-utils/hwclock-cmos.c index f7e8a1811..426ef4c23 100644 --- a/sys-utils/hwclock-cmos.c +++ b/sys-utils/hwclock-cmos.c @@ -393,12 +393,18 @@ static int get_permissions_cmos(void) return rc; } +static get_device_path(void) +{ + return NULL; +} + static struct clock_ops cmos_interface = { N_("Using direct ISA access to the clock"), get_permissions_cmos, read_hardware_clock_cmos, set_hardware_clock_cmos, synchronize_to_clock_tick_cmos, + get_device_path, }; /* diff --git a/sys-utils/hwclock-rtc.c b/sys-utils/hwclock-rtc.c index ef95d9807..3b069d7aa 100644 --- a/sys-utils/hwclock-rtc.c +++ b/sys-utils/hwclock-rtc.c @@ -369,12 +369,18 @@ static int get_permissions_rtc(void) return 0; } +static const char *get_device_path(void) +{ + return rtc_dev_name; +} + static struct clock_ops rtc_interface = { N_("Using the rtc interface to the clock."), get_permissions_rtc, read_hardware_clock_rtc, set_hardware_clock_rtc, synchronize_to_clock_tick_rtc, + get_device_path, }; /* return &rtc if /dev/rtc can be opened, NULL otherwise */ diff --git a/sys-utils/hwclock.8.in b/sys-utils/hwclock.8.in index b9f618973..729b1ddae 100644 --- a/sys-utils/hwclock.8.in +++ b/sys-utils/hwclock.8.in @@ -280,6 +280,24 @@ parameters should be observed. .RE . .TP +.BI \%\-\-delay= seconds +This option allows to overwrite internally used delay when set clock time. The +default is 0.5 (500ms) for rtc_cmos, for another RTC types the delay is 0. If +RTC type is impossible to determine (from sysfs) then it defaults also to 0.5 +to be backwardly compatible. +.RS +.PP +The 500ms default is based on commonly used MC146818A-compatible (x86) hardware clock. This +Hardware Clock can only be set to any integer time plus one half second. The +integer time is required because there is no interface to set or get a +fractional second. The additional half second delay is because the Hardware +Clock updates to the following second precisely 500 ms after setting the new +time. Unfortunately, this behavior is hardware specific and in same cases +another delay is required. +.RE +. +.TP +.TP .BR \-D ", " \-\-debug .RB Use\ \-\-verbose . .RB The\ \%\-\-debug\ option diff --git a/sys-utils/hwclock.c b/sys-utils/hwclock.c index b83e71004..d9acbaf7d 100644 --- a/sys-utils/hwclock.c +++ b/sys-utils/hwclock.c @@ -78,6 +78,8 @@ #include "timeutils.h" #include "env.h" #include "xalloc.h" +#include "path.h" +#include "strutils.h" #ifdef HAVE_LIBAUDIT #include <libaudit.h> @@ -409,6 +411,47 @@ set_hardware_clock(const struct hwclock_control *ctl, const time_t newtime) ur->set_hardware_clock(ctl, &new_broken_time); } +static double +get_hardware_delay(const struct hwclock_control *ctl) +{ + const char *devpath, *rtcname; + char name[128 + 1]; + struct path_cxt *pc; + int rc; + + devpath = ur->get_device_path(); + if (!devpath) + goto unknown; + + rtcname = strrchr(devpath, '/'); + if (!rtcname || !*(rtcname + 1)) + goto unknown; + rtcname++; + + pc = ul_new_path("/sys/class/rtc/%s", rtcname); + if (!pc) + goto unknown; + rc = ul_path_scanf(pc, "name", "%128[^\n ]", &name); + ul_unref_path(pc); + + if (rc != 1 || !*name) + goto unknown; + + if (ctl->verbose) + printf(_("RTC type: '%s'\n"), name); + + /* MC146818A-compatible (x86) */ + if (strcmp(name, "rtc_cmos") == 0) + return 0.5; + + /* Another HW */ + return 0; +unknown: + /* Let's be backwardly compatible */ + return 0.5; +} + + /* * Set the Hardware Clock to the time "sethwtime", in local time zone or * UTC, according to "universal". @@ -418,7 +461,8 @@ set_hardware_clock(const struct hwclock_control *ctl, const time_t newtime) * 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 exactly 2 * seconds since "refsystime") and then set the Hardware Clock to 14:03:07, - * thus getting a precise and retroactive setting of the clock. + * thus getting a precise and retroactive setting of the clock. The .5 delay is + * default on x86, see --delay and get_hardware_delay(). * * (Don't be confused by the fact that the system clock and the Hardware * Clock differ by two hours in the above example. That's just to remind you @@ -480,15 +524,26 @@ set_hardware_clock_exact(const struct hwclock_control *ctl, time_t newhwtime = sethwtime; double target_time_tolerance_secs = 0.001; /* initial value */ double tolerance_incr_secs = 0.001; /* initial value */ - const double RTC_SET_DELAY_SECS = 0.5; /* 500 ms */ - const struct timeval RTC_SET_DELAY_TV = { 0, RTC_SET_DELAY_SECS * 1E6 }; + double delay; + struct timeval rtc_set_delay_tv; struct timeval targetsystime; struct timeval nowsystime; struct timeval prevsystime = refsystime; double deltavstarget; - timeradd(&refsystime, &RTC_SET_DELAY_TV, &targetsystime); + if (ctl->rtc_delay != -1.0) /* --delay specified */ + delay = ctl->rtc_delay; + else + delay = get_hardware_delay(ctl); + + if (ctl->verbose) + printf(_("Using delay: %.6f seconds\n"), delay); + + rtc_set_delay_tv.tv_sec = 0; + rtc_set_delay_tv.tv_usec = delay * 1E6; + + timeradd(&refsystime, &rtc_set_delay_tv, &targetsystime); while (1) { double ticksize; @@ -549,7 +604,7 @@ set_hardware_clock_exact(const struct hwclock_control *ctl, newhwtime = sethwtime + (int)(time_diff(nowsystime, refsystime) - - RTC_SET_DELAY_SECS /* don't count this */ + - delay /* don't count this */ + 0.5 /* for rounding */); if (ctl->verbose) printf(_("%ld.%06ld is close enough to %ld.%06ld (%.6f < %.6f)\n" @@ -1082,6 +1137,7 @@ usage(void) printf(_( " --directisa use the ISA bus instead of %1$s access\n"), _PATH_RTC_DEV); puts(_(" --date <time> date/time input for --set and --predict")); + puts(_(" --delay <sec> delay used when set new RTC time")); #if defined(__linux__) && defined(__alpha__) puts(_(" --epoch <year> epoch input for --setepoch")); #endif @@ -1100,7 +1156,10 @@ usage(void) int main(int argc, char **argv) { - struct hwclock_control ctl = { .show = 1 }; /* default op is show */ + struct hwclock_control ctl = { + .show = 1, /* default op is show */ + .rtc_delay = -1.0 /* unspecified */ + }; struct timeval startup_time; struct adjtime adjtime = { 0 }; struct timespec when = { 0 }; @@ -1115,6 +1174,7 @@ int main(int argc, char **argv) enum { OPT_ADJFILE = CHAR_MAX + 1, OPT_DATE, + OPT_DELAY, OPT_DIRECTISA, OPT_EPOCH, OPT_GET, @@ -1150,6 +1210,7 @@ int main(int argc, char **argv) { "directisa", no_argument, NULL, OPT_DIRECTISA }, { "test", no_argument, NULL, OPT_TEST }, { "date", required_argument, NULL, OPT_DATE }, + { "delay", required_argument, NULL, OPT_DELAY }, #ifdef __linux__ { "rtc", required_argument, NULL, 'f' }, #endif @@ -1271,6 +1332,9 @@ int main(int argc, char **argv) case OPT_DATE: ctl.date_opt = optarg; /* --date */ break; + case OPT_DELAY: + ctl.rtc_delay = strtod_or_err(optarg, "invalid --delay argument"); + break; case OPT_ADJFILE: ctl.adj_file_name = optarg; /* --adjfile */ break; diff --git a/sys-utils/hwclock.h b/sys-utils/hwclock.h index 7bb6ec8bd..92fdb5f82 100644 --- a/sys-utils/hwclock.h +++ b/sys-utils/hwclock.h @@ -22,6 +22,7 @@ UL_DEBUG_DECLARE_MASK(hwclock); struct hwclock_control { char *date_opt; char *adj_file_name; + double rtc_delay; /* --delay <seconds> */ #if defined(__linux__) && defined(__alpha__) char *epoch_option; #endif @@ -58,6 +59,7 @@ struct clock_ops { int (*read_hardware_clock) (const struct hwclock_control *ctl, struct tm * tm); int (*set_hardware_clock) (const struct hwclock_control *ctl, const struct tm * tm); int (*synchronize_to_clock_tick) (const struct hwclock_control *ctl); + const char *(*get_device_path) (void); }; extern struct clock_ops *probe_for_cmos_clock(void); |