View Issue Details

IDProjectCategoryView StatusLast Update
00017941003.1(2016/18)/Issue7+TC2System Interfacespublic2024-01-06 23:11
Reportersteffen Assigned To 
PrioritynormalSeverityEditorialTypeEnhancement Request
Status NewResolutionOpen 
Namesteffen
Organization
User Reference
Sectionlocaltime, gmtime
Page Numberin transit
Line Number(Line or range of lines)
Interp Status
Final Accepted Text
Summary0001794: Please add tzalloc/tzfree and localtime_rz, mktime_z interfaces
Description[I copy a mail from austin-group-l@]

As stated in [1] the localtime() and mktime() series of functions
have the inherent problem of not being thread-safe regarding
possible changes to the time zone: in a pure POSIX environment
changes to TZ always affect global data.

If my memory serves correctly, about a decade ago the NetBSD
project contacted the IANA TZ maintainer in order to upstream
a new, truly thread-safe interface that addresses this issue.
Since some time in 2014 (see [1]) the IANA TZ database, which
includes the Public Domain aka open source code as is used by many
projects to implement the time related programming interface,
includes a new series of functions:

       timezone_t tzalloc(char const *TZ);
       void tzfree(timezone_t tz);

       struct tm *localtime_rz(timezone_t restrict zone,
           time_t const *restrict clock,
           struct tm *restrict result);
           struct tm *restrict tm);
       time_t mktime_z(timezone_t restrict zone,
           struct tm *restrict tm);

  [1] https://austingroupbugs.net/view.php?id=1788

If POSIX would offer this interface, the open source (public
domain) code and manual of which are available via the IANA TZ,
truly "thread-safe" time programming becomes possible in POSIX.

This is especially important if no CLOCK_TAI is available.
For an example, here is what the widely used NTP server chrony
performs in order to achieve its task:

  tm = gmtime(&when);
  if (!tm)
    return tz_leap;

  stm = *tm;

  /* Temporarily switch to the timezone containing leap seconds */
  tz_env = getenv("TZ");
  if (tz_env) {
    if (strlen(tz_env) >= sizeof (tz_orig))
      return tz_leap;
    strcpy(tz_orig, tz_env);
  }
  setenv("TZ", leap_tzname, 1);
  tzset();

  /* Get the TAI-UTC offset, which started at the epoch at 10 seconds */
  t = mktime(&stm);
  if (t != -1)
    tz_tai_offset = t - when + 10;

  /* Set the time to 23:59:60 and see how it overflows in mktime() */
  stm.tm_sec = 60;
  stm.tm_min = 59;
  stm.tm_hour = 23;

  t = mktime(&stm);

  if (tz_env)
    setenv("TZ", tz_orig, 1);
  else
    unsetenv("TZ");
  tzset();

  if (t == -1)
    return tz_leap;

  if (stm.tm_sec == 60)
    tz_leap = LEAP_InsertSecond;
  else if (stm.tm_sec == 1)
    tz_leap = LEAP_DeleteSecond;

  *tai_offset = tz_tai_offset;

This is especially important if no CLOCK_TAI is available.
For an example, here is what the widely used NTP server chrony
performs in order to achieve its task:

  tm = gmtime(&when);
  if (!tm)
    return tz_leap;

  stm = *tm;

  /* Temporarily switch to the timezone containing leap seconds */
  tz_env = getenv("TZ");
  if (tz_env) {
    if (strlen(tz_env) >= sizeof (tz_orig))
      return tz_leap;
    strcpy(tz_orig, tz_env);
  }
  setenv("TZ", leap_tzname, 1);
  tzset();

  /* Get the TAI-UTC offset, which started at the epoch at 10 seconds */
  t = mktime(&stm);
  if (t != -1)
    tz_tai_offset = t - when + 10;

  /* Set the time to 23:59:60 and see how it overflows in mktime() */
  stm.tm_sec = 60;
  stm.tm_min = 59;
  stm.tm_hour = 23;

  t = mktime(&stm);

  if (tz_env)
    setenv("TZ", tz_orig, 1);
  else
    unsetenv("TZ");
  tzset();

  if (t == -1)
    return tz_leap;

  if (stm.tm_sec == 60)
    tz_leap = LEAP_InsertSecond;
  else if (stm.tm_sec == 1)
    tz_leap = LEAP_DeleteSecond;

  *tai_offset = tz_tai_offset;

I want to point out that setting an environment variable can be
a costly operation, but moreover changing the timezone as such
may involve several file system operations, being a potentially
very expensive operation. (By the way the draft 4 uses "file
system" as well as "filesystem".)

With the new interface two timezone objects can be preallocated,
and the operations are totally detached from global data and
multithread-safe.
Desired ActionPlease sponsor and add the tzalloc/tzfree and localtime_rz, mktime_z interfaces.

They are already available on NetBSD, and soon will be released on Android.
The Public Domain code of the IANA TZ includes these functions and their manual pages; its' maintainer is also a major contributor to the most widely used Linux C library (ie a code sync is to be expected fast as necessary).
TagsNo tags attached.

Activities

There are no notes attached to this issue.

Issue History

Date Modified Username Field Change
2024-01-06 23:11 steffen New Issue
2024-01-06 23:11 steffen Name => steffen
2024-01-06 23:11 steffen Section => localtime, gmtime
2024-01-06 23:11 steffen Page Number => in transit
2024-01-06 23:11 steffen Line Number => (Line or range of lines)