> * These need to be made MT-safe:
> 
> mktime, mktime-internal
> timegm
> 
> time_r
> 
> time_rz
> c-nstrftime, nstrftime
> parse-datetime, parse-datetime2

For these modules, the next function to provide in an MT-safe way is
localtime_r. On native Windows, when the 'localtime_s' function [1][2]
is not available, such as on the older Windows versions that Emacs cares
about, the solution is to use GetTimeZoneInformation [3].

The next function, then, is a localtime_r variant with time zone argument.
It's needed
  * for implementing 'localtime_rz', in the 'time_rz' module.
  * as a 'convert' subroutine for the 'mktime_z' function, in the 'time_rz'
    module.
  * indirectly by nstrftime, c-nstrftime, fprintftime, parse-datetime,
    that all rely on 'time_rz'.

Such a localtime_r variant with time zone argument needs to use the
time zone database that the system has access to. But the only public
API that the system offers (localtime{,_r}) relies on the environment "TZ"
variable "TZ" and some global variables (tzname, timezone, daylight)
derived from it, and changing an environment variable is not MT-safe.

So, there are only two approaches that I can see:

  (a) Read the time zone database information into memory from a file
      shipped together with Gnulib. This is how the libstdc++ implementation
      of the C++ time zone functionality [4] does it [5][6].

  (b) Read the time zone database information into memory from the
      system locations, in a platform dependent way.

The code for doing this exists in glibc and libstdc++ and would need to be
adapted.

BUT this is a major project: it would take several weeks.

And it is overkill for
  - the proposed safer_ctime function,
  - most practical uses of nstrftime, c_nstrftime.
Namely, for these cases, a general timezone_t is not needed, only a boolean
that covers the case of local time and GMT/UTC. And these cases *can* be
done in a multithread-safe way:
  - The value of "TZ" does not need to be changed on the fly.
  - The values of the global variables (tzname, timezone, daylight) may
    be set through tzset(), in a thread, but these values are OK for the
    other threads as well, since getenv ("TZ") is the same in all threads.
  - The GMT/UTC case can be implemented by not looking at "TZ" nor the
    global variables.

I therefore intend to do this latter part:
  1) Make localtime_r on native Windows MT-safe.
  2) Document which LGPLed interfaces are not MT-safe.
  3) Provide an MT-safe and bug-fixed 'strftime' function (that assumes
     local time, no time zone argument).
  4) Provide an analogous 'c_strftime' function that does not even access
     "TZ".
  5) The proposed safer_ctime, based on localtime_r and c_strftime.

Bruno

[1] 
https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/localtime-s-localtime32-s-localtime64-s
[2] https://learn.microsoft.com/en-us/previous-versions/a442x3ye
[3] 
https://learn.microsoft.com/en-us/windows/win32/api/timezoneapi/nf-timezoneapi-gettimezoneinformation
[4] https://en.cppreference.com/w/cpp/chrono
[5] 
https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3/include/std/chrono
[6] https://gcc.gnu.org/git/?p=gcc.git;a=tree;f=libstdc%2B%2B-v3/src/c%2B%2B20




Reply via email to