• Oleg Nesterov's avatar
    signal: sigprocmask() should do retarget_shared_pending() · e6fa16ab
    Oleg Nesterov authored
    
    
    In short, almost every changing of current->blocked is wrong, or at least
    can lead to the unexpected results.
    
    For example. Two threads T1 and T2, T1 sleeps in sigtimedwait/pause/etc.
    kill(tgid, SIG) can pick T2 for TIF_SIGPENDING. If T2 calls sigprocmask()
    and blocks SIG before it notices the pending signal, nobody else can handle
    this pending shared signal.
    
    I am not sure this is bug, but at least this looks strange imho. T1 should
    not sleep forever, there is a signal which should wake it up.
    
    This patch moves the code which actually changes ->blocked into the new
    helper, set_current_blocked() and changes this code to call
    retarget_shared_pending() as exit_signals() does. We should only care about
    the signals we just blocked, we use "newset & ~current->blocked" as a mask.
    
    We do not check !sigisemptyset(newblocked), retarget_shared_pending() is
    cheap unless mask & shared_pending.
    
    Note: for this particular case we could simply change sigprocmask() to
    return -EINTR if signal_pending(), but then we should change other callers
    and, more importantly, if we need this fix then set_current_blocked() will
    have more callers and some of them can't restart. See the next patch as a
    random example.
    
    Signed-off-by: default avatarOleg Nesterov <oleg@redhat.com>
    Reviewed-by: default avatarMatt Fleming <matt.fleming@linux.intel.com>
    Acked-by: default avatarTejun Heo <tj@kernel.org>
    e6fa16ab