]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - kernel/signal.c
Merge branch 'ptrace' of git://git.kernel.org/pub/scm/linux/kernel/git/oleg/misc
[karo-tx-linux.git] / kernel / signal.c
index 1ab89f677424fc90ea8d4693bbb7c135b89c1a94..ad5e818baacc43fb5e4046926bf52dde55acacfa 100644 (file)
@@ -238,8 +238,8 @@ static void task_clear_group_stop_trapping(struct task_struct *task)
 {
        if (unlikely(task->group_stop & GROUP_STOP_TRAPPING)) {
                task->group_stop &= ~GROUP_STOP_TRAPPING;
-               __wake_up_sync(&task->parent->signal->wait_chldexit,
-                              TASK_UNINTERRUPTIBLE, 1);
+               __wake_up_sync_key(&task->parent->signal->wait_chldexit,
+                                  TASK_UNINTERRUPTIBLE, 1, task);
        }
 }
 
@@ -669,7 +669,7 @@ static int rm_from_queue_full(sigset_t *mask, struct sigpending *s)
        if (sigisemptyset(&m))
                return 0;
 
-       signandsets(&s->signal, &s->signal, mask);
+       sigandnsets(&s->signal, &s->signal, mask);
        list_for_each_entry_safe(q, n, &s->list, list) {
                if (sigismember(mask, q->info.si_signo)) {
                        list_del_init(&q->list);
@@ -2068,7 +2068,7 @@ relock:
        for (;;) {
                struct k_sigaction *ka;
                /*
-                * Tracing can induce an artifical signal and choose sigaction.
+                * Tracing can induce an artificial signal and choose sigaction.
                 * The return value in @signr determines the default action,
                 * but @info->si_signo is the signal number we will report.
                 */
@@ -2299,6 +2299,18 @@ long do_no_restart_syscall(struct restart_block *param)
        return -EINTR;
 }
 
+static void __set_task_blocked(struct task_struct *tsk, const sigset_t *newset)
+{
+       if (signal_pending(tsk) && !thread_group_empty(tsk)) {
+               sigset_t newblocked;
+               /* A set of now blocked but previously unblocked signals. */
+               sigandnsets(&newblocked, newset, &current->blocked);
+               retarget_shared_pending(tsk, &newblocked);
+       }
+       tsk->blocked = *newset;
+       recalc_sigpending();
+}
+
 /**
  * set_current_blocked - change current->blocked mask
  * @newset: new mask
@@ -2311,14 +2323,7 @@ void set_current_blocked(const sigset_t *newset)
        struct task_struct *tsk = current;
 
        spin_lock_irq(&tsk->sighand->siglock);
-       if (signal_pending(tsk) && !thread_group_empty(tsk)) {
-               sigset_t newblocked;
-               /* A set of now blocked but previously unblocked signals. */
-               signandsets(&newblocked, newset, &current->blocked);
-               retarget_shared_pending(tsk, &newblocked);
-       }
-       tsk->blocked = *newset;
-       recalc_sigpending();
+       __set_task_blocked(tsk, newset);
        spin_unlock_irq(&tsk->sighand->siglock);
 }
 
@@ -2344,7 +2349,7 @@ int sigprocmask(int how, sigset_t *set, sigset_t *oldset)
                sigorsets(&newset, &tsk->blocked, set);
                break;
        case SIG_UNBLOCK:
-               signandsets(&newset, &tsk->blocked, set);
+               sigandnsets(&newset, &tsk->blocked, set);
                break;
        case SIG_SETMASK:
                newset = *set;
@@ -2541,7 +2546,8 @@ int do_sigtimedwait(const sigset_t *which, siginfo_t *info,
                /*
                 * None ready, temporarily unblock those we're interested
                 * while we are sleeping in so that we'll be awakened when
-                * they arrive.
+                * they arrive. Unblocking is always fine, we can avoid
+                * set_current_blocked().
                 */
                tsk->real_blocked = tsk->blocked;
                sigandsets(&tsk->blocked, &tsk->blocked, &mask);
@@ -2551,10 +2557,9 @@ int do_sigtimedwait(const sigset_t *which, siginfo_t *info,
                timeout = schedule_timeout_interruptible(timeout);
 
                spin_lock_irq(&tsk->sighand->siglock);
-               sig = dequeue_signal(tsk, &mask, info);
-               tsk->blocked = tsk->real_blocked;
+               __set_task_blocked(tsk, &tsk->real_blocked);
                siginitset(&tsk->real_blocked, 0);
-               recalc_sigpending();
+               sig = dequeue_signal(tsk, &mask, info);
        }
        spin_unlock_irq(&tsk->sighand->siglock);
 
@@ -2884,60 +2889,51 @@ SYSCALL_DEFINE1(sigpending, old_sigset_t __user *, set)
 /**
  *  sys_sigprocmask - examine and change blocked signals
  *  @how: whether to add, remove, or set signals
- *  @set: signals to add or remove (if non-null)
+ *  @nset: signals to add or remove (if non-null)
  *  @oset: previous value of signal mask if non-null
  *
  * Some platforms have their own version with special arguments;
  * others support only sys_rt_sigprocmask.
  */
 
-SYSCALL_DEFINE3(sigprocmask, int, how, old_sigset_t __user *, set,
+SYSCALL_DEFINE3(sigprocmask, int, how, old_sigset_t __user *, nset,
                old_sigset_t __user *, oset)
 {
-       int error;
        old_sigset_t old_set, new_set;
+       sigset_t new_blocked;
 
-       if (set) {
-               error = -EFAULT;
-               if (copy_from_user(&new_set, set, sizeof(*set)))
-                       goto out;
+       old_set = current->blocked.sig[0];
+
+       if (nset) {
+               if (copy_from_user(&new_set, nset, sizeof(*nset)))
+                       return -EFAULT;
                new_set &= ~(sigmask(SIGKILL) | sigmask(SIGSTOP));
 
-               spin_lock_irq(&current->sighand->siglock);
-               old_set = current->blocked.sig[0];
+               new_blocked = current->blocked;
 
-               error = 0;
                switch (how) {
-               default:
-                       error = -EINVAL;
-                       break;
                case SIG_BLOCK:
-                       sigaddsetmask(&current->blocked, new_set);
+                       sigaddsetmask(&new_blocked, new_set);
                        break;
                case SIG_UNBLOCK:
-                       sigdelsetmask(&current->blocked, new_set);
+                       sigdelsetmask(&new_blocked, new_set);
                        break;
                case SIG_SETMASK:
-                       current->blocked.sig[0] = new_set;
+                       new_blocked.sig[0] = new_set;
                        break;
+               default:
+                       return -EINVAL;
                }
 
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-               if (error)
-                       goto out;
-               if (oset)
-                       goto set_old;
-       } else if (oset) {
-               old_set = current->blocked.sig[0];
-       set_old:
-               error = -EFAULT;
+               set_current_blocked(&new_blocked);
+       }
+
+       if (oset) {
                if (copy_to_user(oset, &old_set, sizeof(*oset)))
-                       goto out;
+                       return -EFAULT;
        }
-       error = 0;
-out:
-       return error;
+
+       return 0;
 }
 #endif /* __ARCH_WANT_SYS_SIGPROCMASK */
 
@@ -2945,8 +2941,8 @@ out:
 /**
  *  sys_rt_sigaction - alter an action taken by a process
  *  @sig: signal to be sent
- *  @act: the thread group ID of the thread
- *  @oact: the PID of the thread
+ *  @act: new sigaction
+ *  @oact: used to save the previous sigaction
  *  @sigsetsize: size of sigset_t type
  */
 SYSCALL_DEFINE4(rt_sigaction, int, sig,