> * 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