|
@@ -172,6 +172,17 @@ void recalc_sigpending(void)
|
|
|
|
|
|
}
|
|
|
|
|
|
+void calculate_sigpending(void)
|
|
|
+{
|
|
|
+ /* Have any signals or users of TIF_SIGPENDING been delayed
|
|
|
+ * until after fork?
|
|
|
+ */
|
|
|
+ spin_lock_irq(¤t->sighand->siglock);
|
|
|
+ set_tsk_thread_flag(current, TIF_SIGPENDING);
|
|
|
+ recalc_sigpending();
|
|
|
+ spin_unlock_irq(¤t->sighand->siglock);
|
|
|
+}
|
|
|
+
|
|
|
/* Given the mask, find the first available signal that should be serviced. */
|
|
|
|
|
|
#define SYNCHRONOUS_MASK \
|
|
@@ -362,6 +373,20 @@ static bool task_participate_group_stop(struct task_struct *task)
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+void task_join_group_stop(struct task_struct *task)
|
|
|
+{
|
|
|
+ /* Have the new thread join an on-going signal group stop */
|
|
|
+ unsigned long jobctl = current->jobctl;
|
|
|
+ if (jobctl & JOBCTL_STOP_PENDING) {
|
|
|
+ struct signal_struct *sig = current->signal;
|
|
|
+ unsigned long signr = jobctl & JOBCTL_STOP_SIGMASK;
|
|
|
+ unsigned long gstop = JOBCTL_STOP_PENDING | JOBCTL_STOP_CONSUME;
|
|
|
+ if (task_set_jobctl_pending(task, signr | gstop)) {
|
|
|
+ sig->group_stop_count++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* allocate a new signal queue record
|
|
|
* - this may be called without locks if and only if t == current, otherwise an
|
|
@@ -895,7 +920,7 @@ static inline int wants_signal(int sig, struct task_struct *p)
|
|
|
return task_curr(p) || !signal_pending(p);
|
|
|
}
|
|
|
|
|
|
-static void complete_signal(int sig, struct task_struct *p, int group)
|
|
|
+static void complete_signal(int sig, struct task_struct *p, enum pid_type type)
|
|
|
{
|
|
|
struct signal_struct *signal = p->signal;
|
|
|
struct task_struct *t;
|
|
@@ -908,7 +933,7 @@ static void complete_signal(int sig, struct task_struct *p, int group)
|
|
|
*/
|
|
|
if (wants_signal(sig, p))
|
|
|
t = p;
|
|
|
- else if (!group || thread_group_empty(p))
|
|
|
+ else if ((type == PIDTYPE_PID) || thread_group_empty(p))
|
|
|
/*
|
|
|
* There is just one thread and it does not need to be woken.
|
|
|
* It will dequeue unblocked signals before it runs again.
|
|
@@ -998,7 +1023,7 @@ static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_str
|
|
|
#endif
|
|
|
|
|
|
static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
|
|
|
- int group, int from_ancestor_ns)
|
|
|
+ enum pid_type type, int from_ancestor_ns)
|
|
|
{
|
|
|
struct sigpending *pending;
|
|
|
struct sigqueue *q;
|
|
@@ -1012,7 +1037,7 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
|
|
|
from_ancestor_ns || (info == SEND_SIG_FORCED)))
|
|
|
goto ret;
|
|
|
|
|
|
- pending = group ? &t->signal->shared_pending : &t->pending;
|
|
|
+ pending = (type != PIDTYPE_PID) ? &t->signal->shared_pending : &t->pending;
|
|
|
/*
|
|
|
* Short-circuit ignored signals and support queuing
|
|
|
* exactly one non-rt signal, so that we can get more
|
|
@@ -1096,14 +1121,29 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
|
|
|
out_set:
|
|
|
signalfd_notify(t, sig);
|
|
|
sigaddset(&pending->signal, sig);
|
|
|
- complete_signal(sig, t, group);
|
|
|
+
|
|
|
+ /* Let multiprocess signals appear after on-going forks */
|
|
|
+ if (type > PIDTYPE_TGID) {
|
|
|
+ struct multiprocess_signals *delayed;
|
|
|
+ hlist_for_each_entry(delayed, &t->signal->multiprocess, node) {
|
|
|
+ sigset_t *signal = &delayed->signal;
|
|
|
+ /* Can't queue both a stop and a continue signal */
|
|
|
+ if (sig == SIGCONT)
|
|
|
+ sigdelsetmask(signal, SIG_KERNEL_STOP_MASK);
|
|
|
+ else if (sig_kernel_stop(sig))
|
|
|
+ sigdelset(signal, SIGCONT);
|
|
|
+ sigaddset(signal, sig);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ complete_signal(sig, t, type);
|
|
|
ret:
|
|
|
- trace_signal_generate(sig, info, t, group, result);
|
|
|
+ trace_signal_generate(sig, info, t, type != PIDTYPE_PID, result);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
|
|
|
- int group)
|
|
|
+ enum pid_type type)
|
|
|
{
|
|
|
int from_ancestor_ns = 0;
|
|
|
|
|
@@ -1112,7 +1152,7 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
|
|
|
!task_pid_nr_ns(current, task_active_pid_ns(t));
|
|
|
#endif
|
|
|
|
|
|
- return __send_signal(sig, info, t, group, from_ancestor_ns);
|
|
|
+ return __send_signal(sig, info, t, type, from_ancestor_ns);
|
|
|
}
|
|
|
|
|
|
static void print_fatal_signal(int signr)
|
|
@@ -1151,23 +1191,23 @@ __setup("print-fatal-signals=", setup_print_fatal_signals);
|
|
|
int
|
|
|
__group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
|
|
|
{
|
|
|
- return send_signal(sig, info, p, 1);
|
|
|
+ return send_signal(sig, info, p, PIDTYPE_TGID);
|
|
|
}
|
|
|
|
|
|
static int
|
|
|
specific_send_sig_info(int sig, struct siginfo *info, struct task_struct *t)
|
|
|
{
|
|
|
- return send_signal(sig, info, t, 0);
|
|
|
+ return send_signal(sig, info, t, PIDTYPE_PID);
|
|
|
}
|
|
|
|
|
|
int do_send_sig_info(int sig, struct siginfo *info, struct task_struct *p,
|
|
|
- bool group)
|
|
|
+ enum pid_type type)
|
|
|
{
|
|
|
unsigned long flags;
|
|
|
int ret = -ESRCH;
|
|
|
|
|
|
if (lock_task_sighand(p, &flags)) {
|
|
|
- ret = send_signal(sig, info, p, group);
|
|
|
+ ret = send_signal(sig, info, p, type);
|
|
|
unlock_task_sighand(p, &flags);
|
|
|
}
|
|
|
|
|
@@ -1274,7 +1314,8 @@ struct sighand_struct *__lock_task_sighand(struct task_struct *tsk,
|
|
|
/*
|
|
|
* send signal info to all the members of a group
|
|
|
*/
|
|
|
-int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
|
|
|
+int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p,
|
|
|
+ enum pid_type type)
|
|
|
{
|
|
|
int ret;
|
|
|
|
|
@@ -1283,7 +1324,7 @@ int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
|
|
|
rcu_read_unlock();
|
|
|
|
|
|
if (!ret && sig)
|
|
|
- ret = do_send_sig_info(sig, info, p, true);
|
|
|
+ ret = do_send_sig_info(sig, info, p, type);
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
@@ -1301,7 +1342,7 @@ int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp)
|
|
|
success = 0;
|
|
|
retval = -ESRCH;
|
|
|
do_each_pid_task(pgrp, PIDTYPE_PGID, p) {
|
|
|
- int err = group_send_sig_info(sig, info, p);
|
|
|
+ int err = group_send_sig_info(sig, info, p, PIDTYPE_PGID);
|
|
|
success |= !err;
|
|
|
retval = err;
|
|
|
} while_each_pid_task(pgrp, PIDTYPE_PGID, p);
|
|
@@ -1317,7 +1358,7 @@ int kill_pid_info(int sig, struct siginfo *info, struct pid *pid)
|
|
|
rcu_read_lock();
|
|
|
p = pid_task(pid, PIDTYPE_PID);
|
|
|
if (p)
|
|
|
- error = group_send_sig_info(sig, info, p);
|
|
|
+ error = group_send_sig_info(sig, info, p, PIDTYPE_TGID);
|
|
|
rcu_read_unlock();
|
|
|
if (likely(!p || error != -ESRCH))
|
|
|
return error;
|
|
@@ -1376,7 +1417,7 @@ int kill_pid_info_as_cred(int sig, struct siginfo *info, struct pid *pid,
|
|
|
|
|
|
if (sig) {
|
|
|
if (lock_task_sighand(p, &flags)) {
|
|
|
- ret = __send_signal(sig, info, p, 1, 0);
|
|
|
+ ret = __send_signal(sig, info, p, PIDTYPE_TGID, 0);
|
|
|
unlock_task_sighand(p, &flags);
|
|
|
} else
|
|
|
ret = -ESRCH;
|
|
@@ -1420,7 +1461,8 @@ static int kill_something_info(int sig, struct siginfo *info, pid_t pid)
|
|
|
for_each_process(p) {
|
|
|
if (task_pid_vnr(p) > 1 &&
|
|
|
!same_thread_group(p, current)) {
|
|
|
- int err = group_send_sig_info(sig, info, p);
|
|
|
+ int err = group_send_sig_info(sig, info, p,
|
|
|
+ PIDTYPE_MAX);
|
|
|
++count;
|
|
|
if (err != -EPERM)
|
|
|
retval = err;
|
|
@@ -1446,7 +1488,7 @@ int send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
|
|
|
if (!valid_signal(sig))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- return do_send_sig_info(sig, info, p, false);
|
|
|
+ return do_send_sig_info(sig, info, p, PIDTYPE_PID);
|
|
|
}
|
|
|
|
|
|
#define __si_special(priv) \
|
|
@@ -1664,17 +1706,20 @@ void sigqueue_free(struct sigqueue *q)
|
|
|
__sigqueue_free(q);
|
|
|
}
|
|
|
|
|
|
-int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group)
|
|
|
+int send_sigqueue(struct sigqueue *q, struct pid *pid, enum pid_type type)
|
|
|
{
|
|
|
int sig = q->info.si_signo;
|
|
|
struct sigpending *pending;
|
|
|
+ struct task_struct *t;
|
|
|
unsigned long flags;
|
|
|
int ret, result;
|
|
|
|
|
|
BUG_ON(!(q->flags & SIGQUEUE_PREALLOC));
|
|
|
|
|
|
ret = -1;
|
|
|
- if (!likely(lock_task_sighand(t, &flags)))
|
|
|
+ rcu_read_lock();
|
|
|
+ t = pid_task(pid, type);
|
|
|
+ if (!t || !likely(lock_task_sighand(t, &flags)))
|
|
|
goto ret;
|
|
|
|
|
|
ret = 1; /* the signal is ignored */
|
|
@@ -1696,15 +1741,16 @@ int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group)
|
|
|
q->info.si_overrun = 0;
|
|
|
|
|
|
signalfd_notify(t, sig);
|
|
|
- pending = group ? &t->signal->shared_pending : &t->pending;
|
|
|
+ pending = (type != PIDTYPE_PID) ? &t->signal->shared_pending : &t->pending;
|
|
|
list_add_tail(&q->list, &pending->list);
|
|
|
sigaddset(&pending->signal, sig);
|
|
|
- complete_signal(sig, t, group);
|
|
|
+ complete_signal(sig, t, type);
|
|
|
result = TRACE_SIGNAL_DELIVERED;
|
|
|
out:
|
|
|
- trace_signal_generate(sig, &q->info, t, group, result);
|
|
|
+ trace_signal_generate(sig, &q->info, t, type != PIDTYPE_PID, result);
|
|
|
unlock_task_sighand(t, &flags);
|
|
|
ret:
|
|
|
+ rcu_read_unlock();
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -3193,7 +3239,7 @@ do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info)
|
|
|
* probe. No signal is actually delivered.
|
|
|
*/
|
|
|
if (!error && sig) {
|
|
|
- error = do_send_sig_info(sig, info, p, false);
|
|
|
+ error = do_send_sig_info(sig, info, p, PIDTYPE_PID);
|
|
|
/*
|
|
|
* If lock_task_sighand() failed we pretend the task
|
|
|
* dies after receiving the signal. The window is tiny,
|
|
@@ -3960,7 +4006,7 @@ void kdb_send_sig(struct task_struct *t, int sig)
|
|
|
"the deadlock.\n");
|
|
|
return;
|
|
|
}
|
|
|
- ret = send_signal(sig, SEND_SIG_PRIV, t, false);
|
|
|
+ ret = send_signal(sig, SEND_SIG_PRIV, t, PIDTYPE_PID);
|
|
|
spin_unlock(&t->sighand->siglock);
|
|
|
if (ret)
|
|
|
kdb_printf("Fail to deliver Signal %d to process %d.\n",
|