no dead-lock when signal handler calls localtime_r() on FreeBSD, but on Linux

Erwan Legrand freebsd at
Mon Oct 2 09:03:54 UTC 2017

On Mon, Oct 2, 2017 at 9:10 AM, Matthias Apitz <guru at> wrote:
> El día Monday, October 02, 2017 a las 09:57:51AM +0300, Yuri Pankov escribió:
>> On Mon, 2 Oct 2017 08:34:26 +0200, Matthias Apitz wrote:
>> >I'm on the way clarifying a deadlock-issue we face on Linux when localtime_r()
>> >is called in a signal-handler funtion. If you compile the code attached
>> >below with gcc on Linux, the code gives what one deserves: a dead-lock
>> >when Ctrl-C is pressed.
>> Why? I don't see anything explicitly stating that localtime_r() is
>> async-signal-UNsafe.
> Because, as I said, it is not in the list of
>      The following functions are either reentrant or not interruptible by
>      signals and are async-signal safe.  Therefore applications may invoke
>      them, without restriction, from signal-catching functions or from a child
>      process after calling fork(2) in a multi-threaded process:
> in the man page sigactio(2).

So what?

Calling async-safe functions in signal handlers will not by itself
trigger a bug. (Unless there is a bug in the implementation.) That is
what a guarantee that async-safe functions (and standards) give.

Assuming that calling in a signal handler functions which are not
labeled as async-safe by some standard will reproducibility trigger a
bug is faulty logic. Doing so *may* trigger a bug, but that is *not* a
guaranteed behavior.

localtime_r() is guaranteed to be thread-safe. It is not guaranteed to
be async-safe. This suggest that the function might not be truly
reentrant. It is only guaranteed to be reentrant with regard to thread
safety. Async-safety requires reentrancy in a strictest sense.

The implementation of localtime_r() in glibc is a good example as it
calls a function named __tz_convert() which itself acquires a lock
which makes it unsuitable for use within a signal handler.

In the case of FreeBSD, a read-write lock is used and locatime_r()
locks it as a reader. As multiple readers are allowed, this does not
block in your case. Still, calling localtime_r() in a signal handler
will block if the lock is acquired by a writer.

Do not call async-unsafe functions in signal handlers. *Just don't!*

More information about the freebsd-questions mailing list