summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorDave McCracken <dmccr@us.ibm.com>2002-02-05 18:39:27 -0800
committerLinus Torvalds <torvalds@penguin.transmeta.com>2002-02-05 18:39:27 -0800
commit676952b9bd85d03929922c101352a5677979f9e6 (patch)
treeb2e05cfcaa27cca4b004e21d0c04ef35f630b653 /kernel
parent040fdeaf4cd38a0c0154eef22e085d0efd2f3219 (diff)
[PATCH] Third version of signal changes for thread groups
During the course of developing our pthread library (the NGPT pthread library) it became clear we needed some kernel support for handling signals. This patch helps the library by redirecting all signals sent to tasks in a thread group to the thread group leader. It also defines the tkill() system call so the library can signal a specific task if necessary. Given that as far as I know NGPT is the only user of thread groups, and that this change would benefit any other user of thread groups, I'm submitting this for inclusion in the 2.5 kernel. Note that this patch also adds support for sys_gettid() for the architectures that don't have it. While this could have been split into a spearate patch, it would create conflicts since this patch also adds sys_tkill(), so I felt it was cleaner to leave them together. Dave McCracken ====================================================================== Dave McCracken IBM Linux Base Kernel Team 1-512-838-3059 dmccr@us.ibm.com T/L 678-3059
Diffstat (limited to 'kernel')
-rw-r--r--kernel/fork.c4
-rw-r--r--kernel/signal.c72
2 files changed, 71 insertions, 5 deletions
diff --git a/kernel/fork.c b/kernel/fork.c
index 8c10cad0e021..bfbae1b15439 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -724,10 +724,10 @@ int do_fork(unsigned long clone_flags, unsigned long stack_start,
/* Need tasklist lock for parent etc handling! */
write_lock_irq(&tasklist_lock);
- /* CLONE_PARENT and CLONE_THREAD re-use the old parent */
+ /* CLONE_PARENT re-uses the old parent */
p->p_opptr = current->p_opptr;
p->p_pptr = current->p_pptr;
- if (!(clone_flags & (CLONE_PARENT | CLONE_THREAD))) {
+ if (!(clone_flags & CLONE_PARENT)) {
p->p_opptr = current;
if (!(p->ptrace & PT_PTRACED))
p->p_pptr = current;
diff --git a/kernel/signal.c b/kernel/signal.c
index 3741c8a4a6ac..d648cff08eb6 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -142,6 +142,35 @@ flush_signal_handlers(struct task_struct *t)
}
}
+/*
+ * sig_exit - cause the current task to exit due to a signal.
+ */
+
+void
+sig_exit(int sig, int exit_code, struct siginfo *info)
+{
+ struct task_struct *t;
+
+ sigaddset(&current->pending.signal, sig);
+ recalc_sigpending(current);
+ current->flags |= PF_SIGNALED;
+
+ /* Propagate the signal to all the tasks in
+ * our thread group
+ */
+ if (info && (unsigned long)info != 1
+ && info->si_code != SI_TKILL) {
+ read_lock(&tasklist_lock);
+ for_each_thread(t) {
+ force_sig_info(sig, info, t);
+ }
+ read_unlock(&tasklist_lock);
+ }
+
+ do_exit(exit_code);
+ /* NOTREACHED */
+}
+
/* Notify the system that a driver wants to block all signals for this
* process, and wants to be notified if any signals at all were to be
* sent/acted upon. If the notifier routine returns non-zero, then the
@@ -589,7 +618,7 @@ kill_pg_info(int sig, struct siginfo *info, pid_t pgrp)
retval = -ESRCH;
read_lock(&tasklist_lock);
for_each_task(p) {
- if (p->pgrp == pgrp) {
+ if (p->pgrp == pgrp && thread_group_leader(p)) {
int err = send_sig_info(sig, info, p);
if (retval)
retval = err;
@@ -636,8 +665,15 @@ kill_proc_info(int sig, struct siginfo *info, pid_t pid)
read_lock(&tasklist_lock);
p = find_task_by_pid(pid);
error = -ESRCH;
- if (p)
+ if (p) {
+ if (!thread_group_leader(p)) {
+ struct task_struct *tg;
+ tg = find_task_by_pid(p->tgid);
+ if (tg)
+ p = tg;
+ }
error = send_sig_info(sig, info, p);
+ }
read_unlock(&tasklist_lock);
return error;
}
@@ -660,7 +696,7 @@ static int kill_something_info(int sig, struct siginfo *info, int pid)
read_lock(&tasklist_lock);
for_each_task(p) {
- if (p->pid > 1 && p != current) {
+ if (p->pid > 1 && p != current && thread_group_leader(p)) {
int err = send_sig_info(sig, info, p);
++count;
if (err != -EPERM)
@@ -985,6 +1021,36 @@ sys_kill(int pid, int sig)
return kill_something_info(sig, &info, pid);
}
+/*
+ * Kill only one task, even if it's a CLONE_THREAD task.
+ */
+asmlinkage long
+sys_tkill(int pid, int sig)
+{
+ struct siginfo info;
+ int error;
+ struct task_struct *p;
+
+ /* This is only valid for single tasks */
+ if (pid <= 0)
+ return -EINVAL;
+
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = SI_TKILL;
+ info.si_pid = current->pid;
+ info.si_uid = current->uid;
+
+ read_lock(&tasklist_lock);
+ p = find_task_by_pid(pid);
+ error = -ESRCH;
+ if (p) {
+ error = send_sig_info(sig, &info, p);
+ }
+ read_unlock(&tasklist_lock);
+ return error;
+}
+
asmlinkage long
sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo)
{