Fix: Use a filled signal mask to disable all signals
Changelog from David Pelton's original patch:
While using lttng-ust with an application that was calling fork()
with pending signals, I found that all signals were getting unmasked
shortly before the underlying call to fork(). After some
investigation, I found that the rcu_bp_before_fork() function was
unmasking all signals. Based on the comments for this function, it
should be masking all signals. Inspection of the rest of the code
in urcu-bp.c revealed the same pattern in two other functions.
This patch changes the code to use a filled signal mask to disable
all signals. The change to rcu_bp_before_fork() addressed the
problem I was seeing while using lttng-ust. The changes to the
other two functions appear to fix other instances of the same
problem.
Updates by Mathieu Desnoyers:
- Use SIG_BLOCK instead of SIG_SETMASK when setting a filled mask. This
has the same behavior in this case (since we're blocking all signals),
but is semantically neater: if we ever some signals from that mask,
we'd like to to a union with the signal mask already blocked by the
application.
- Also fix incorrect signal masking in compat_arch_x86.c.
These currently translate into simple compiler barriers on all
architectures, but the and/or/add/sub/inc/dec uatomics do not provide
memory ordering guarantees (only uatomic_add_return, uatomic_sub_return,
uatomic_xchg, and uatomic_cmpxchg provides full memory barrier
guarantees before and after the atomic operations).
Passing an unsigned int to uatomic_sub does not honor sign extend to
long, as we should be allowed by assume.
Fix this by introducing caa_cast_long_keep_sign(), which casts either to
long or unsigned long depending on the signedness of the argument
received. It is used in uatomic_sub before applying the "-" operator,
since this operator needs to operate on the "long" type size (since sign
extension might not be performed if the argument received is unsigned).
Discourage use of pthread_atfork() for call_rcu handlers
Discourage use of glibc pthread_atfork() for call_rcu handlers due to
its inappropriate assumptions about single-threadedness while pthread
atfork handlers are executing. This results in hangs within the glibc
memory allocator.
Reviewed-by: Paul E. McKenney <email address hidden>
Signed-off-by: Mathieu Desnoyers <email address hidden>
Fix call_rcu fork handling by putting all call_rcu threads in a
quiescent state before fork (paused state), and unpausing them when the
parent returns from fork.
On the child, everything will run fine as long as we don't issue fork()
from a call_rcu callback.
Side-note: pthread_atfork is not appropriate when using with multithread
and malloc/free. The glibc malloc implementation sadly expects that all
malloc/free are executed from the context of a single thread while
pthread atfork handlers are running, which leads to interesting hang in
glibc.