diff options
| author | Dave McCracken <dmccr@us.ibm.com> | 2002-02-05 18:39:27 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@penguin.transmeta.com> | 2002-02-05 18:39:27 -0800 |
| commit | 676952b9bd85d03929922c101352a5677979f9e6 (patch) | |
| tree | b2e05cfcaa27cca4b004e21d0c04ef35f630b653 /kernel | |
| parent | 040fdeaf4cd38a0c0154eef22e085d0efd2f3219 (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.c | 4 | ||||
| -rw-r--r-- | kernel/signal.c | 72 |
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(¤t->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) { |
