Adds a solution to the problem of the real signal mask having a signal unblocked in a thread where the app has it blocked, while another app thread has it unblocked, when the kernel delivers a group-wide signal.
To avoid checking all threads on every blocked signal, which requires heavyweight locks that can't be acquired from our signal handler, we maintain a count of unmasked threads for each signal number. This is shared across the handler group and is updated using atomic operations.
On arrival of a signal blocked by the app, we first detect whether it is whole-group-directed, by examining the si_code values. If it is, and if the unmasked thread count is > 0, we want to re-route it: but we can't acquire the locks here, so we mark it unblocked, unlink the interrupted fragment (if any), and head back through dispatch with the signals_pending flag set.
Once in the pending-signal code from dispatch, we grab the thread_initexit_lock and walk the threads, looking for a thread with this signal unblocked. For synchronization with other threads' masks, we can't have a mutex used on every access as we need lock-free reads from our signal handler. Instead, we have a mutex used only on writes (only done by the owning thread) and on reads from other threads (just this rerouting code).
Once we find a target thread, we send it a new signal and drop the current one. This will properly interrupt any syscall. This should be an asynchronous signal, so a new later copy should be fine.
We handle sigqueue's extra value by using SYS_rt_tgsigqueueinfo where available.
Adds a new test linux.sigmask which tests both kill() and sigqueue(). Enables previously-disabled alarms in the api.static_signal to further test the fix.
Future improvements include keeping the actual mask matching the app's mask, if DR and clients don't care about that signal: which will require an API addition.
Issue: #2311