Is there a signal safe alternative to localtime_r()?
Question
We've got some code to do crawl the stack, and it's very handy to be able to dump the current time when we do so. Unfortunately, while the localtime_r()
function is reentrant, it is not signal safe, and we see it calling internal pthread mutex functions on some platforms:
0: c000000000436b90 : __ksleep() + 0x30 (/usr/lib/hpux64/libc.so.1)
1: c000000000152060 : __spin_lock_spin() + 0x1b0 (/usr/lib/hpux64/libpthread.so.1)
2: c0000000001d3da0 : __pth_bound() + 0x160 (/usr/lib/hpux64/libpthread.so.1)
3: c0000000001d9080 : __mxn_wakeup() + 0x140 (/usr/lib/hpux64/libpthread.so.1)
4: c0000000001429a0 : __pthread_mutex_unlock_ng() + 0x940 (/usr/lib/hpux64/libpthread.so.1)
5: c000000000142040 : pthread_mutex_unlock() + 0x20 (/usr/lib/hpux64/libpthread.so.1)
6: c000000000458370 : __thread_mutex_unlock() + 0xb0 (/usr/lib/hpux64/libc.so.1)
7: c000000000321cd0 : __localtime_r_posix() + 0x7e0 (/usr/lib/hpux64/libc.so.1)
We can dump the time safely by calling just gettimeofday()
(omitting the "pretty-printing of the time with the followup localtime_r()
call) and then post processing the stack trace file. There are some difficulties with that idea, and it would be nice to avoid that if possible.
Without requiring post-processing outside of the signal handler, are there any known other ways to achieve a localtime
like result that are signal safe?
Solution
I came up with a workaround for this problem. Call localtime
in a different thread for the process outside of a signal context and cache the value after clearing the hour/min/sec fields (along with the mktime
result for that manipulated struct tm
).
As long as I have a value from within the 24 hour period since the last cached value, I can consume it in the signal handler, manually constructing a struct tm
for the gettimeofday
in the handler by adding back in the hour/min/sec fields for the delta from the cached point in time.
It's not perfect, and there's some tricky aspects to ensuring I don't read a value that's being updated while the handler executes, but I can avoid post processing the post mortem dump file in most cases, and not trap or hang due to signal unsafe functions in the handler.