|
WG14 threadsafe signals
|
(C) 2024 - 2025 Niall Douglas http://www.nedproductions.biz/
Can be configured to be a standard library implementation for your standard C library runtime. Licensed permissively.
This library should work well on any POSIX implementation, as well as Microsoft Windows. You will need a minimum of C 11 in your toolchain. Every architecture supporting C 11 atomics should work.
Current CI test targets:
Current compilers:
You can find a number of user definable macros to override in config.h. They have sensible defaults on the major platforms and toolchains.
The only one to be especially aware of is WG14_SIGNALS_HAVE_ASYNC_SAFE_THREAD_LOCAL. If your platform and toolchain has async signal safe thread local storage, it can be used instead of a hash table which is much, much faster. Current platform status for this support can be read all about at https://maskray.me/blog/2021-02-14-all-about-thread-local-storage, but to summarise:
initial-exec TLS attribute, which we turn on for all GNU toolchains except on Apple ones. IF your libc reserves static TLS space for runtime loaded shared libraries (e.g. glibc), you can incorporate this library into runtime loaded shared libraries without issue. If it does not, runtime loading a shared library will fail. In this case, either place this library in a process bootstrap shared library or the program library, or force disable off use of async safe thread locals.tss_async_signal_safe_get() which implements an async signal safe thread local storage using a hash table costs about 8 nanoseconds, so maybe 29 clock cycles.With WG14_SIGNALS_HAVE_ASYNC_SAFE_THREAD_LOCAL=1 (the default on Linux, Windows, and other ELF based platforms):
- `thrd_signal_invoke()` which invokes a function which thread locally
handles any signals raised costs about 16 nanoseconds (31 clock cycles) for the happy case (most of this is the cost of _setjmp() on this platform and glibc).
- A globally installed signal decider takes about 8 nanoseconds (29
clock cycles) to reach (there is a CAS lock-unlock sequence needed).
With WG14_SIGNALS_HAVE_ASYNC_SAFE_THREAD_LOCAL=0:
- `thrd_signal_invoke()` which invokes a function which thread locally
handles any signals raised costs about 25 nanoseconds for the happy case.
- A globally installed signal decider takes about 10 nanoseconds to reach.
tss_async_signal_safe_get() which implements an async signal safe thread local storage using a hash table costs about 16 nanoseconds.thrd_signal_invoke() which invokes a function which thread locally handles any signals raised costs about 20 nanoseconds for the happy case (most of this is the cost of _setjmp() on this platform and libc).tss_async_signal_safe_get() which implements an async signal safe thread local storage using a hash table costs about 22 nanoseconds.thrd_signal_invoke() which invokes a function which thread locally handles any signals raised costs about 17 nanoseconds (this is Windows Structured Exception Handling, not our library code).