[PATCH] Simpler signal-exit concurrency handling
authorPaul E. McKenney <paulmck@us.ibm.com>
Sun, 8 Jan 2006 09:01:38 +0000 (01:01 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 9 Jan 2006 04:13:40 +0000 (20:13 -0800)
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>
kernel/signal.c

index 64737c7..9b6fda5 100644 (file)
@@ -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;