Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
[pandora-kernel.git] / kernel / signal.c
index 6ea13c0..a4077e9 100644 (file)
@@ -277,6 +277,7 @@ void task_clear_jobctl_trapping(struct task_struct *task)
 {
        if (unlikely(task->jobctl & JOBCTL_TRAPPING)) {
                task->jobctl &= ~JOBCTL_TRAPPING;
+               smp_mb();       /* advised by wake_up_bit() */
                wake_up_bit(&task->jobctl, JOBCTL_TRAPPING_BIT);
        }
 }
@@ -705,11 +706,8 @@ void signal_wake_up_state(struct task_struct *t, unsigned int state)
  * Returns 1 if any signals were found.
  *
  * All callers must be holding the siglock.
- *
- * This version takes a sigset mask and looks at all signals,
- * not just those in the first mask word.
  */
-static int rm_from_queue_full(sigset_t *mask, struct sigpending *s)
+static int flush_sigqueue_mask(sigset_t *mask, struct sigpending *s)
 {
        struct sigqueue *q, *n;
        sigset_t m;
@@ -727,29 +725,6 @@ static int rm_from_queue_full(sigset_t *mask, struct sigpending *s)
        }
        return 1;
 }
-/*
- * Remove signals in mask from the pending set and queue.
- * Returns 1 if any signals were found.
- *
- * All callers must be holding the siglock.
- */
-static int rm_from_queue(unsigned long mask, struct sigpending *s)
-{
-       struct sigqueue *q, *n;
-
-       if (!sigtestsetmask(&s->signal, mask))
-               return 0;
-
-       sigdelsetmask(&s->signal, mask);
-       list_for_each_entry_safe(q, n, &s->list, list) {
-               if (q->info.si_signo < SIGRTMIN &&
-                   (mask & sigmask(q->info.si_signo))) {
-                       list_del_init(&q->list);
-                       __sigqueue_free(q);
-               }
-       }
-       return 1;
-}
 
 static inline int is_si_special(const struct siginfo *info)
 {
@@ -861,6 +836,7 @@ static bool prepare_signal(int sig, struct task_struct *p, bool force)
 {
        struct signal_struct *signal = p->signal;
        struct task_struct *t;
+       sigset_t flush;
 
        if (signal->flags & (SIGNAL_GROUP_EXIT | SIGNAL_GROUP_COREDUMP)) {
                if (signal->flags & SIGNAL_GROUP_COREDUMP)
@@ -872,26 +848,25 @@ static bool prepare_signal(int sig, struct task_struct *p, bool force)
                /*
                 * This is a stop signal.  Remove SIGCONT from all queues.
                 */
-               rm_from_queue(sigmask(SIGCONT), &signal->shared_pending);
-               t = p;
-               do {
-                       rm_from_queue(sigmask(SIGCONT), &t->pending);
-               } while_each_thread(p, t);
+               siginitset(&flush, sigmask(SIGCONT));
+               flush_sigqueue_mask(&flush, &signal->shared_pending);
+               for_each_thread(p, t)
+                       flush_sigqueue_mask(&flush, &t->pending);
        } else if (sig == SIGCONT) {
                unsigned int why;
                /*
                 * Remove all stop signals from all queues, wake all threads.
                 */
-               rm_from_queue(SIG_KERNEL_STOP_MASK, &signal->shared_pending);
-               t = p;
-               do {
+               siginitset(&flush, SIG_KERNEL_STOP_MASK);
+               flush_sigqueue_mask(&flush, &signal->shared_pending);
+               for_each_thread(p, t) {
+                       flush_sigqueue_mask(&flush, &t->pending);
                        task_clear_jobctl_pending(t, JOBCTL_STOP_PENDING);
-                       rm_from_queue(SIG_KERNEL_STOP_MASK, &t->pending);
                        if (likely(!(t->ptrace & PT_SEIZED)))
                                wake_up_state(t, __TASK_STOPPED);
                        else
                                ptrace_trap_notify(t);
-               } while_each_thread(p, t);
+               }
 
                /*
                 * Notify the parent with CLD_CONTINUED if we were stopped.
@@ -2854,7 +2829,7 @@ int do_sigtimedwait(const sigset_t *which, siginfo_t *info,
 
                spin_lock_irq(&tsk->sighand->siglock);
                __set_task_blocked(tsk, &tsk->real_blocked);
-               siginitset(&tsk->real_blocked, 0);
+               sigemptyset(&tsk->real_blocked);
                sig = dequeue_signal(tsk, &mask, info);
        }
        spin_unlock_irq(&tsk->sighand->siglock);
@@ -3091,18 +3066,39 @@ COMPAT_SYSCALL_DEFINE4(rt_tgsigqueueinfo,
 }
 #endif
 
+/*
+ * For kthreads only, must not be used if cloned with CLONE_SIGHAND
+ */
+void kernel_sigaction(int sig, __sighandler_t action)
+{
+       spin_lock_irq(&current->sighand->siglock);
+       current->sighand->action[sig - 1].sa.sa_handler = action;
+       if (action == SIG_IGN) {
+               sigset_t mask;
+
+               sigemptyset(&mask);
+               sigaddset(&mask, sig);
+
+               flush_sigqueue_mask(&mask, &current->signal->shared_pending);
+               flush_sigqueue_mask(&mask, &current->pending);
+               recalc_sigpending();
+       }
+       spin_unlock_irq(&current->sighand->siglock);
+}
+EXPORT_SYMBOL(kernel_sigaction);
+
 int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
 {
-       struct task_struct *t = current;
+       struct task_struct *p = current, *t;
        struct k_sigaction *k;
        sigset_t mask;
 
        if (!valid_signal(sig) || sig < 1 || (act && sig_kernel_only(sig)))
                return -EINVAL;
 
-       k = &t->sighand->action[sig-1];
+       k = &p->sighand->action[sig-1];
 
-       spin_lock_irq(&current->sighand->siglock);
+       spin_lock_irq(&p->sighand->siglock);
        if (oact)
                *oact = *k;
 
@@ -3121,21 +3117,20 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
                 *   (for example, SIGCHLD), shall cause the pending signal to
                 *   be discarded, whether or not it is blocked"
                 */
-               if (sig_handler_ignored(sig_handler(t, sig), sig)) {
+               if (sig_handler_ignored(sig_handler(p, sig), sig)) {
                        sigemptyset(&mask);
                        sigaddset(&mask, sig);
-                       rm_from_queue_full(&mask, &t->signal->shared_pending);
-                       do {
-                               rm_from_queue_full(&mask, &t->pending);
-                       } while_each_thread(current, t);
+                       flush_sigqueue_mask(&mask, &p->signal->shared_pending);
+                       for_each_thread(p, t)
+                               flush_sigqueue_mask(&mask, &t->pending);
                }
        }
 
-       spin_unlock_irq(&current->sighand->siglock);
+       spin_unlock_irq(&p->sighand->siglock);
        return 0;
 }
 
-static int 
+static int
 do_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, unsigned long sp)
 {
        stack_t oss;
@@ -3496,7 +3491,7 @@ COMPAT_SYSCALL_DEFINE3(sigaction, int, sig,
 }
 #endif
 
-#ifdef __ARCH_WANT_SYS_SGETMASK
+#ifdef CONFIG_SGETMASK_SYSCALL
 
 /*
  * For backwards compatibility.  Functionality superseded by sigprocmask.
@@ -3517,7 +3512,7 @@ SYSCALL_DEFINE1(ssetmask, int, newmask)
 
        return old;
 }
-#endif /* __ARCH_WANT_SGETMASK */
+#endif /* CONFIG_SGETMASK_SYSCALL */
 
 #ifdef __ARCH_WANT_SYS_SIGNAL
 /*