Search code examples
cglibclibc

Why does gmtime_r call __tz_convert which grabs a global lock?


I was surprised to see that gmtime_r is calling tz-anything really. I figure the reason there is a localtime vs gmtime is taht the former does tz conversions whereas the latter need not. Looks like gmtime calls __tz_convert though, which then goes ahead and grabs a global lock on the tz ( which dont even really need ... right? ) Am I missing something here? How can I get efficient conversion of epoch -> struct tm in a multithreaded application?

(gdb) where
#0  0x00007fffee255eec in __lll_lock_wait_private () from /lib64/libc.so.6
#1  0x00007fffee2007bc in _L_lock_2546 () from /lib64/libc.so.6
#2  0x00007fffee2005f7 in __tz_convert () from /lib64/libc.so.6
#3  0x000000000041c63f in DateTimeEx (dt=..., this=0x7fffca551900) at /var/lib/jenkins/workspace/hfalgo_src_hotfix_1.69.1-T6J4HNFQDMYVEKV4MEGVD6UCCPG7KHWQDOSVYBUDROFXZA6YINSA/hfalgo_src/./core/Time.h:81

Solution

  • glibc can process timezone database files which contain leap second information, and gmtime and gmtime_r take these leap seconds into account. (For example, the Debian tzdata package provides such time zone files in the /usr/share/zoneinfo/right directory.) This is why the glibc implementation reads the time zone database and performs some locking related to that.

    I am not aware of anyone actually using the leap second functionality. POSIX currently requires that the count since epoch does not take into account any leap seconds, so using data files with leap seconds results in non-conforming behavior of functions such as gmtime.

    However, I expect that some non-portable software relies on the fact that calling gmtime or gmtime_r performs an implicit tzset call, thereby initializing tzname and other global variables. This is a larger barrier to eliminating locking from the current implementation. (Someone even posted a bounty for this, but at 100 USD it is totally disproportionate to the effort required to fix this.)

    If you need to avoid the lock today, you need to look up the gmtime algorithm (Calendrical Calculations is an interesting reference for these questions) and implement it yourself.