Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=7bb44adef39ad3bda2be40bb34686bc56bd563a5
Commit:     7bb44adef39ad3bda2be40bb34686bc56bd563a5
Parent:     3c6df2a9177c010bf811c361149069e4bfd9bb11
Author:     Roland McGrath <[EMAIL PROTECTED]>
AuthorDate: Wed May 23 13:57:44 2007 -0700
Committer:  Linus Torvalds <[EMAIL PROTECTED]>
CommitDate: Wed May 23 20:14:12 2007 -0700

    recalc_sigpending_tsk fixes
    
    Steve Hawkes discovered a problem where recalc_sigpending_tsk was called in
    do_sigaction but no signal_wake_up call was made, preventing later signals
    from waking up blocked threads with TIF_SIGPENDING already set.
    
    In fact, the few other calls to recalc_sigpending_tsk outside the signals
    code are also subject to this problem in other race conditions.
    
    This change makes recalc_sigpending_tsk private to the signals code.  It
    changes the outside calls, as well as do_sigaction, to use the new
    recalc_sigpending_and_wake instead.
    
    Signed-off-by: Roland McGrath <[EMAIL PROTECTED]>
    Cc: <[EMAIL PROTECTED]>
    Cc: Oleg Nesterov <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
---
 include/linux/sched.h  |   12 +++++++-----
 kernel/exit.c          |    7 ++-----
 kernel/power/process.c |    2 +-
 kernel/signal.c        |   24 ++++++++++++++++++------
 4 files changed, 28 insertions(+), 17 deletions(-)

diff --git a/include/linux/sched.h b/include/linux/sched.h
index 870b75e..d58e74b 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1616,11 +1616,13 @@ static inline int lock_need_resched(spinlock_t *lock)
        return 0;
 }
 
-/* Reevaluate whether the task has signals pending delivery.
-   This is required every time the blocked sigset_t changes.
-   callers must hold sighand->siglock.  */
-
-extern FASTCALL(void recalc_sigpending_tsk(struct task_struct *t));
+/*
+ * Reevaluate whether the task has signals pending delivery.
+ * Wake the task if so.
+ * This is required every time the blocked sigset_t changes.
+ * callers must hold sighand->siglock.
+ */
+extern void recalc_sigpending_and_wake(struct task_struct *t);
 extern void recalc_sigpending(void);
 
 extern void signal_wake_up(struct task_struct *t, int resume_stopped);
diff --git a/kernel/exit.c b/kernel/exit.c
index c6d14b8..5b888c2 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -762,11 +762,8 @@ static void exit_notify(struct task_struct *tsk)
                read_lock(&tasklist_lock);
                spin_lock_irq(&tsk->sighand->siglock);
                for (t = next_thread(tsk); t != tsk; t = next_thread(t))
-                       if (!signal_pending(t) && !(t->flags & PF_EXITING)) {
-                               recalc_sigpending_tsk(t);
-                               if (signal_pending(t))
-                                       signal_wake_up(t, 0);
-                       }
+                       if (!signal_pending(t) && !(t->flags & PF_EXITING))
+                               recalc_sigpending_and_wake(t);
                spin_unlock_irq(&tsk->sighand->siglock);
                read_unlock(&tasklist_lock);
        }
diff --git a/kernel/power/process.c b/kernel/power/process.c
index d31d638..e0233d8 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -101,7 +101,7 @@ static void cancel_freezing(struct task_struct *p)
                pr_debug("  clean up: %s\n", p->comm);
                do_not_freeze(p);
                spin_lock_irqsave(&p->sighand->siglock, flags);
-               recalc_sigpending_tsk(p);
+               recalc_sigpending_and_wake(p);
                spin_unlock_irqrestore(&p->sighand->siglock, flags);
        }
 }
diff --git a/kernel/signal.c b/kernel/signal.c
index 364fc95..acdfc05 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -96,15 +96,27 @@ static inline int has_pending_signals(sigset_t *signal, 
sigset_t *blocked)
 
 #define PENDING(p,b) has_pending_signals(&(p)->signal, (b))
 
-fastcall void recalc_sigpending_tsk(struct task_struct *t)
+static int recalc_sigpending_tsk(struct task_struct *t)
 {
        if (t->signal->group_stop_count > 0 ||
            (freezing(t)) ||
            PENDING(&t->pending, &t->blocked) ||
-           PENDING(&t->signal->shared_pending, &t->blocked))
+           PENDING(&t->signal->shared_pending, &t->blocked)) {
                set_tsk_thread_flag(t, TIF_SIGPENDING);
-       else
-               clear_tsk_thread_flag(t, TIF_SIGPENDING);
+               return 1;
+       }
+       clear_tsk_thread_flag(t, TIF_SIGPENDING);
+       return 0;
+}
+
+/*
+ * After recalculating TIF_SIGPENDING, we need to make sure the task wakes up.
+ * This is superfluous when called on current, the wakeup is a harmless no-op.
+ */
+void recalc_sigpending_and_wake(struct task_struct *t)
+{
+       if (recalc_sigpending_tsk(t))
+               signal_wake_up(t, 0);
 }
 
 void recalc_sigpending(void)
@@ -744,7 +756,7 @@ force_sig_info(int sig, struct siginfo *info, struct 
task_struct *t)
                action->sa.sa_handler = SIG_DFL;
                if (blocked) {
                        sigdelset(&t->blocked, sig);
-                       recalc_sigpending_tsk(t);
+                       recalc_sigpending_and_wake(t);
                }
        }
        ret = specific_send_sig_info(sig, info, t);
@@ -2273,7 +2285,7 @@ int do_sigaction(int sig, struct k_sigaction *act, struct 
k_sigaction *oact)
                        rm_from_queue_full(&mask, &t->signal->shared_pending);
                        do {
                                rm_from_queue_full(&mask, &t->pending);
-                               recalc_sigpending_tsk(t);
+                               recalc_sigpending_and_wake(t);
                                t = next_thread(t);
                        } while (t != current);
                }
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to