[PROPOSED] Support FreeBSD-style TZif polling
I installed the attached proposed patch, which adds a tzcode option to periodically poll the TZif file to see whether it changed. You can enable this option by compiling with -DTZ_CHANGE_INTERVAL=61 (or choose your own favorite polling interval instead of 61 seconds). The option affects localtime and other functions whose behavior depends on the TZ environment variable (or its absence); it does not affect tzalloc-related functions. This patch affects tzcode's behavior only if you compile with the new option. The remaining major difference between the functionalities of tzcode and FreeBSD is FreeBSD's support for calling localtime (not localtime_r) from multiple threads. I plan to take a look at that some time soon, with the idea of adding that as another tzcode option. While preparing this patch I noticed some issues in FreeBSD localtime.c, noted below. The attached patch addresses these issues. * A bug can occur in the first minute after reboot, where FreeBSD’s tzdata_is_fresh assumes that since the monotonic clock is less than 61, the cache must be fresh. * Prefer CLOCK_MONOTONIC_COARSE aka CLOCK_MONOTONIC_FAST if available, as its precision suffices here and it should be more efficient than CLOCK_MONOTONIC. * When checking the file timestamp, the code should not fail merely because fstat fails due to EOVERFLOW. Instead, it should assume the file has changed, as this results in better behavior for the user. * When checking the file timestamp the code should not use strlcpy to copy its name. The strlcpy could silently truncate the name in the unlikely case where a relative file name is shorter than PATH_MAX but the absolute file name is not. More importantly, the file contents are what matter here, and since the file name does not matter there is no need to copy it. * It’s a bit better to check st_ctim, not just st_ctime, as st_ctim has subsecond resolution and is more likely to avoid false matches on platforms with dicey st_dev or st_ino. * For efficiency do not bother checking st_mtim/st_mtime, as st_ctim is updated whenever st_mtim is. * For efficiency do not call fstat twice in the unlikely case where TZ is an absolute pathname. * tzdata_is_fresh is poorly named, as it returns 0 if the cache is fresh, 1 if not. And as a nit, in traditional English, “data” is a plural word. The attached patch uses a function fresh_tzdata instead, with the more common interpretation of true and false. * The attached patch ports to platforms with 32-bit time_t and without tm_gmtoff. On these platforms, strftime.c includes localtime.c and localtime.h uses ‘#define time_t timex_t’. For this reason, fresh_tzdata cannot use time_t (which might be timex_t); it needs to use the underlying system time_t. * The attached patch ports to platforms lacking <sys/stat.h>, struct timespec, clock_gettime, or CLOCK_MONOTONIC/CLOCK_MONOTONIC_COARSE.
Paul Eggert via tz wrote in <d7550ba3-b637-43c3-b189-a824f22b6bbd@cs.ucla.edu>: |I installed the attached proposed patch, which adds a tzcode option to |periodically poll the TZif file to see whether it changed. You can What a terrible thing, isn't it. It is optional as you say. You know, if it would be a possibility to install a handler, so that all the many programs which actually run an eventloop can simply integrate the one in likely the set of the not-few paths that are monitored (often, at least; like resolv.conf, hosts, and what do i know on the many XDG config places that possibly even exist, mailcap etcetc). Like eg tz_hook(enum act{install,uninstall,trigger}, (*hook)(?), char const * const * path_(to_)watch(ed)), or something. And use the poll code if no hook is set? |enable this option by compiling with -DTZ_CHANGE_INTERVAL=61 (or choose |your own favorite polling interval instead of 61 seconds). The option |affects localtime and other functions whose behavior depends on the TZ |environment variable (or its absence); it does not affect |tzalloc-related functions. | |This patch affects tzcode's behavior only if you compile with the new |option. ... I mean, i such poll monitors myself, but it can be wrong for X seconds, and what sense does this make, then? And i would assume many frameworks have a central notification mechanism .. i recall having used for example KDE around maybe 2001/2 at early stages, and it was quite thrilling to change the language aka locale and see that (slow) event wave in the UI. Isn't it horror to have buried so-and-so many such poll notifiers in buried library paths. And what if i do not care at all. A nice Sunday from Germany i wish, --steffen | |Der Kragenbaer, The moon bear, |der holt sich munter he cheerfully and one by one |einen nach dem anderen runter wa.ks himself off |(By Robert Gernhardt)
On Oct 4, 2025, at 4:22 PM, Steffen Nurpmeso via tz <tz@iana.org> wrote:
What a terrible thing, isn't it. It is optional as you say. You know, if it would be a possibility to install a handler, so that all the many programs which actually run an eventloop
In macOS, even programs that *don't* explicitly set up an event loop get notified of changes to the current time zone setting, and update; try, for example, a program that sleeps for 5 seconds, calls time(), and prints the result of ctime() on the returned value. I'll change the time it's printing if you change the system time zone. I don't think the notifications are delivered if the OS's update mechanism installs an update to the tz files, however. Deborah? The tzcode in macOS checks for change notifications in various internal routines (internal routines used by tzset() and tzsetwall(), and getsub() as used by localtime(). This uses macOS's notify(3) mechanism, in particular notify_check(), which I think sends a (Mach) message to the notification daemon asking whether a notification has been posted (it doesn't wait for one to be posted).
On 2025-10-04 20:12, Guy Harris via tz wrote:
This uses macOS's notify(3) mechanism, in particular notify_check()
Thanks, I didn't know that. Perhaps this idea should also be incorporated into tzcode localtime.c; it shouldn't be that hard to add it as an alternative to FreeBSD's polling.
macOS also checks struct stat's st_gen, which is easy and seems like a good idea on platforms that have st_gen. Proposed tzcode patch attached and installed in the GitHub repository.
On Oct 5, 2025, at 5:20 PM, Paul Eggert <eggert@cs.ucla.edu> wrote:
macOS also checks struct stat's st_gen, which is easy and seems like a good idea on platforms that have st_gen.
So all the 4.4-Lite derivatives, i.e. (Free,Net,Open,DragonFly}BSD as well as Darwin, and maybe others.
On Oct 5, 2025, at 7:40 PM, Paul Eggert <eggert@cs.ucla.edu> wrote:
On 2025-10-05 19:10, Guy Harris wrote:
So all the 4.4-Lite derivatives, i.e. (Free,Net,Open,DragonFly}BSD as well as Darwin, and maybe others.
Yes, though I haven't worried about DragonFlyBSD in the recent changes, as I don't know which of the BSDish features it supports.
st_gen, at least, appears to come from 4.4-Lite2 (and maybe 4.4-Lite), at least according to the 4.4-Lite2 source from https://github.com/sergev/4.4BSD-Lite2, so it's in all of the *BSDs (I have repositories of all), including CupertinoBSD. Having forked from FreeBSD, DragonFly BSD probably has a feature set significantly overlapping with FreeBSD, although not identical to FreeBSD.
I note that the macOS (15.6) manual includes the caveat: The file generation number, st_gen, is only available to the super-user. I don't know if that applies to the *BSD releases. I don't know how much of a problem that is for the proposed TZ code. On Sun, Oct 5, 2025 at 8:10 PM Guy Harris via tz <tz@iana.org> wrote:
On Oct 5, 2025, at 5:20 PM, Paul Eggert <eggert@cs.ucla.edu> wrote:
macOS also checks struct stat's st_gen, which is easy and seems like a good idea on platforms that have st_gen.
So all the 4.4-Lite derivatives, i.e. (Free,Net,Open,DragonFly}BSD as well as Darwin, and maybe others.
-- Jonathan Leffler <jonathan.leffler@gmail.com> #include <disclaimer.h> Guardian of DBD::Informix - v2018.1031 - http://dbi.perl.org "Blessed are we who can laugh at ourselves, for we shall never cease to be amused."
On 2025-10-05 20:24, Jonathan Leffler wrote:
I note that the macOS (15.6) manual includes the caveat:
The file generation number, st_gen, is only available to the super-user.
Ouch, and I now see that Darwin's use of st_gen was withdrawn from its localtime.c sometime between Libc-262 (2002) and Libc-320 (2003). So it sounds like I should withdraw the use of st_gen from tzcode as well. Thanks for mentioning this.
On Oct 5, 2025, at 8:24 PM, Jonathan Leffler <jonathan.leffler@gmail.com> wrote:
I note that the macOS (15.6) manual includes the caveat:
The file generation number, st_gen, is only available to the super-user.
I don't know if that applies to the *BSD releases.
FreeBSD and OpenBSD appear to expose it to non-root users. NetBSD appears to return 0 - the vnode operation for a file system returns it, but vn_stat() in kern/vfs_vnops.c ignores it. I think the original intent in supporting it in the node operations was to allow *NFS servers* to access it and return ESTALE if the generation count in the file handle doesn't match the generation count of the file to which it purports to refer. I don't have access to SunOS [234].x source, so I can't check whether it let the generation number/sequence number for a file escape kernel mode, but Illumos, which is the closest thing I have to SunOS 5.x source, has va_seq as the equivalent of va_gen in vnode attributes, but does not have anything in the stat structure to export it to userland. So, on at least some *BSDs, such as NetBSD nd CupertinoBSD, will often or always return 0, although others may not. (And a quick look at the last version of the HFS+ code in CupertinoBSD doesn't show any sign that it even exports va_gen to callers from above the vnode layer; the NFS server code in the version of XNU appears to use a *separate* vnode generation-countish attribute, but only for cookies in NFSv3.)
I don't know how much of a problem that is for the proposed TZ code.
At most, I think it means that, on some platforms, you won't be able to detect the case wherein a version of the TZif file in question was removed and replaced with a different one *that happened to get the same inode number as the previous one* - but the code would presumably also be checking for the modification and node-change time, which would presumably normally catch that case. I'm not sure how likely that is to be a problem for commonly-used file systems.
On 2025-10-06 01:08, Guy Harris wrote:
I think the original intent in supporting it in the node operations was to allow *NFS servers* to access it and return ESTALE
Ah, thanks, that pretty much explains it. So this wasn't intended for general (non-root) use and it's out-of-place in localtime.c. I have reverted the change in the development repository on GitHub.
At most, I think it means that, on some platforms, you won't be able to detect the case wherein a version of the TZif file in question was removed and replaced with a different one *that happened to get the same inode number as the previous one* - but the code would presumably also be checking for the modification and node-change time, which would presumably normally catch that case. Yes, we check st_ctim (node-change time), which should suffice on POSIX platforms, since it changes whenever st_mtim (modification time) does.
On Oct 5, 2025, at 4:41 PM, Paul Eggert <eggert@cs.ucla.edu> wrote:
On 2025-10-04 20:12, Guy Harris via tz wrote:
This uses macOS's notify(3) mechanism, in particular notify_check()
Thanks, I didn't know that. Perhaps this idea should also be incorporated into tzcode localtime.c; it shouldn't be that hard to add it as an alternative to FreeBSD's polling.
I.e., use Apple's notify_check() calls when building for macOS?
participants (4)
-
Guy Harris -
Jonathan Leffler -
Paul Eggert -
Steffen Nurpmeso