diff options
author | 2006-01-08 01:01:38 -0800 | |
---|---|---|
committer | 2006-01-08 20:13:40 -0800 | |
commit | 2d89c929078588aa9b9c674ef03ee9aa816b59b8 (patch) | |
tree | 129971e5c75545c53236be294f521ec6e7021a2d /kernel/signal.c | |
parent | [PATCH] RCU signal handling (diff) | |
download | linux-2d89c929078588aa9b9c674ef03ee9aa816b59b8.tar.gz linux-2d89c929078588aa9b9c674ef03ee9aa816b59b8.tar.bz2 linux-2d89c929078588aa9b9c674ef03ee9aa816b59b8.zip |
[PATCH] Simpler signal-exit concurrency handling
Some simplification in checking signal delivery against concurrent exit.
Instead of using get_task_struct_rcu(), which increments the task_struct
reference count, check the reference count after acquiring sighand lock.
Signed-off-by: "Paul E. McKenney" <paulmck@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel/signal.c')
-rw-r--r-- | kernel/signal.c | 11 |
1 files changed, 6 insertions, 5 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index 64737c72dadd..9b6fda5e87f1 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1102,18 +1102,19 @@ int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) retry: ret = check_kill_permission(sig, info, p); - if (!ret && sig && (sp = p->sighand)) { - if (!get_task_struct_rcu(p)) - return -ESRCH; + if (!ret && sig && (sp = rcu_dereference(p->sighand))) { spin_lock_irqsave(&sp->siglock, flags); if (p->sighand != sp) { spin_unlock_irqrestore(&sp->siglock, flags); - put_task_struct(p); goto retry; } + if ((atomic_read(&sp->count) == 0) || + (atomic_read(&p->usage) == 0)) { + spin_unlock_irqrestore(&sp->siglock, flags); + return -ESRCH; + } ret = __group_send_sig_info(sig, info, p); spin_unlock_irqrestore(&sp->siglock, flags); - put_task_struct(p); } return ret; |