https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=a0634931f181e9b46818f6fda15d6c28583dccbb
commit a0634931f181e9b46818f6fda15d6c28583dccbb Author: Corinna Vinschen <cori...@vinschen.de> AuthorDate: Fri Jul 18 14:06:16 2025 +0200 Commit: Corinna Vinschen <cori...@vinschen.de> CommitDate: Fri Jul 18 14:06:16 2025 +0200 Cygwin: clocks: read leap secs from /etc/leapsecs on older systems Systems prior to W10 1803 don't have the leapsecs registry key HKLM\SYSTEM\CurrentControlSet\Control\LeapSecondInformation and don't handle leap seconds at all. Given that new leap seconds are a rather seldom, irregular event, drop reading from /usr/share/zoneinfo/leapseconds. Just read the same leap second records from a file /etc/leapsecs as stored in the LeapSeconds registry value on newer systems instead. As a sidenote, the code reading from /usr/share/zoneinfo/leapseconds was wrong anyway, because it didn't take the timestamps into account. Given IERS publishes new leap seconds about 6 months before they occur, CLOCK_TAI would have been one second off for up to 6 months. /etc/leapsecs doesn't exist yet, so we just default to 37 secs. If new leap seconds get provided for newer systems, make sure to provide the /etc/leapsecs file as part of the Cygwin distro with identical entries. Fixes: 2abb929f0ad2 ("Cygwin: clocks: Implement CLOCK_TAI") Signed-off-by: Corinna Vinschen <cori...@vinschen.de> Diff: --- winsup/cygwin/clock.cc | 88 ++++++++++++++++++++++---------------------------- 1 file changed, 39 insertions(+), 49 deletions(-) diff --git a/winsup/cygwin/clock.cc b/winsup/cygwin/clock.cc index 007657472961..5a4109c7ac03 100644 --- a/winsup/cygwin/clock.cc +++ b/winsup/cygwin/clock.cc @@ -1,10 +1,11 @@ #include "winsup.h" +#include <unistd.h> +#include <fcntl.h> #include <realtimeapiset.h> #include "pinfo.h" #include "clock.h" #include "miscfuncs.h" #include "registry.h" -#include <stdio.h> static inline LONGLONG system_qpc_tickspersec () @@ -66,6 +67,8 @@ struct reg_leap_secs_t void inline clk_tai_t::init () { + size_t size = 0; + /* Avoid a lock/unlock sequence */ if (leap_secs) return; @@ -91,66 +94,53 @@ clk_tai_t::init () we always ignore the file! */ if (!reg.error ()) { - size_t size = 0; - if (!NT_SUCCESS (reg.get_binary (L"LeapSeconds", reg_leap_secs, sizeof reg_leap_secs, size))) { ReleaseSRWLockExclusive (&leap_lock); return; } - - size /= sizeof reg_leap_secs[0]; - for (size_t i = 0; i < size; ++i) - { - struct tm tm = { tm_sec: 59, - tm_min: 59, - tm_hour: 23, - tm_mday: reg_leap_secs[i].day, - tm_mon: reg_leap_secs[i].month - 1, - tm_year: reg_leap_secs[i].year - 1900, - tm_wday: 0, - tm_yday: 0, - tm_isdst: 0, - tm_gmtoff: 0, - tm_zone: 0 - }; - /* Future timestamp? We're done. Note that the leap sec is - second 60, therefore <=, not <! */ - if (time (NULL) <= timegm (&tm)) - break; - leap_secs += reg_leap_secs[i].negative ? -1 : 1; - } } + /* Windows 8.1 and W10 prior to 1803. When (if) IERS adds new leap secs, + we'll create a file /etc/leapsecs in the same format as the aforementioned + registry value used on newer OSes. */ else { - FILE *fp = fopen ("/usr/share/zoneinfo/leapseconds", "r"); - if (fp) + int fd = open ("/etc/leapsecs", O_RDONLY); + + if (fd < 0) { - char buf[256]; - - leap_secs = 10; /* Leap secs 1972 */ - while (fgets (buf, sizeof buf, fp)) - { - if (buf[0] != 'L') - continue; - if (strlen (buf) < 30) - continue; - switch (buf[26]) - { - case '+': - ++leap_secs; - break; - case '-': - --leap_secs; - break; - default: - break; - } - } - fclose (fp); + ReleaseSRWLockExclusive (&leap_lock); + return; } + size = (size_t) read (fd, reg_leap_secs, sizeof reg_leap_secs); + if ((ssize_t) size < 0) + size = 0; + close (fd); + } + + size /= sizeof reg_leap_secs[0]; + for (size_t i = 0; i < size; ++i) + { + struct tm tm = { tm_sec: 59, + tm_min: 59, + tm_hour: 23, + tm_mday: reg_leap_secs[i].day, + tm_mon: reg_leap_secs[i].month - 1, + tm_year: reg_leap_secs[i].year - 1900, + tm_wday: 0, + tm_yday: 0, + tm_isdst: 0, + tm_gmtoff: 0, + tm_zone: 0 + }; + /* Future timestamp? We're done. Note that the leap sec is + second 60, therefore <=, not <! */ + if (time (NULL) <= timegm (&tm)) + break; + leap_secs += reg_leap_secs[i].negative ? -1 : 1; } + ReleaseSRWLockExclusive (&leap_lock); }