siginfo_t *info);
 extern long do_sigpending(void __user *, unsigned long);
 extern int sigprocmask(int, sigset_t *, sigset_t *);
+extern void set_current_blocked(const sigset_t *);
 extern int show_unhandled_signals;
 
 struct pt_regs;
 
        return -EINTR;
 }
 
+/**
+ * set_current_blocked - change current->blocked mask
+ * @newset: new mask
+ *
+ * It is wrong to change ->blocked directly, this helper should be used
+ * to ensure the process can't miss a shared signal we are going to block.
+ */
+void set_current_blocked(const sigset_t *newset)
+{
+       struct task_struct *tsk = current;
+
+       spin_lock_irq(&tsk->sighand->siglock);
+       if (signal_pending(tsk) && !thread_group_empty(tsk)) {
+               sigset_t newblocked;
+               /* A set of now blocked but previously unblocked signals. */
+               signandsets(&newblocked, newset, ¤t->blocked);
+               retarget_shared_pending(tsk, &newblocked);
+       }
+       tsk->blocked = *newset;
+       recalc_sigpending();
+       spin_unlock_irq(&tsk->sighand->siglock);
+}
+
 /*
  * This is also useful for kernel threads that want to temporarily
  * (or permanently) block certain signals.
                return -EINVAL;
        }
 
-       spin_lock_irq(&tsk->sighand->siglock);
-       tsk->blocked = newset;
-       recalc_sigpending();
-       spin_unlock_irq(&tsk->sighand->siglock);
-
+       set_current_blocked(&newset);
        return 0;
 }