summaryrefslogtreecommitdiffstats
path: root/kernel/signal.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-03-27 23:54:12 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-03-27 23:54:12 +0000
commitd3e71cb08747743fce908122bab08b479eb403a5 (patch)
treecbec6948fdbdee9af81cf3ecfb504070d2745d7b /kernel/signal.c
parentfe7ff1706e323d0e5ed83972960a1ecc1ee538b3 (diff)
Merge with Linux 2.3.99-pre3.
Diffstat (limited to 'kernel/signal.c')
-rw-r--r--kernel/signal.c94
1 files changed, 67 insertions, 27 deletions
diff --git a/kernel/signal.c b/kernel/signal.c
index 55017e2f6..0958af05c 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -90,7 +90,7 @@ flush_signal_handlers(struct task_struct *t)
* Dequeue a signal and return the element to the caller, which is
* expected to free it.
*
- * All callers of must be holding current->sigmask_lock.
+ * All callers must be holding current->sigmask_lock.
*/
int
@@ -149,19 +149,19 @@ printk("SIG dequeue (%s:%d): %d ", current->comm, current->pid,
kmem_cache_free(signal_queue_cachep,q);
atomic_dec(&nr_queued_signals);
- /* then see if this signal is still pending. */
- q = *pp;
- while (q) {
- if (q->info.si_signo == sig) {
- reset = 0;
- break;
- }
- q = q->next;
- }
+ /* Then see if this signal is still pending.
+ (Non rt signals may not be queued twice.)
+ */
+ if (sig >= SIGRTMIN)
+ for (q = *pp; q; q = q->next)
+ if (q->info.si_signo == sig) {
+ reset = 0;
+ break;
+ }
+
} else {
- /* Ok, it wasn't in the queue. It must have
- been sent either by a non-rt mechanism and
- we ran out of queue space. So zero out the
+ /* Ok, it wasn't in the queue. We must have
+ been out of queue space. So zero out the
info. */
info->si_signo = sig;
info->si_errno = 0;
@@ -170,9 +170,10 @@ printk("SIG dequeue (%s:%d): %d ", current->comm, current->pid,
info->si_uid = 0;
}
- if (reset)
+ if (reset) {
sigdelset(&current->signal, sig);
- recalc_sigpending(current);
+ recalc_sigpending(current);
+ }
/* XXX: Once POSIX.1b timers are in, if si_code == SI_TIMER,
we need to xchg out the timer overrun values. */
@@ -196,6 +197,43 @@ printk(" %d -> %d\n", signal_pending(current), sig);
}
/*
+ * Remove signal sig from queue and from t->signal.
+ * Returns 1 if sig was found in t->signal.
+ *
+ * All callers must be holding t->sigmask_lock.
+ */
+static int rm_sig_from_queue(int sig, struct task_struct *t)
+{
+ struct signal_queue *q, **pp;
+
+ if (sig >= SIGRTMIN) {
+ printk(KERN_CRIT "SIG: rm_sig_from_queue() doesn't support rt signals\n");
+ return 0;
+ }
+
+ if (!sigismember(&t->signal, sig))
+ return 0;
+
+ sigdelset(&t->signal, sig);
+
+ pp = &t->sigqueue;
+ q = t->sigqueue;
+
+ /* Find the one we're interested in ...
+ It may appear only once. */
+ for ( ; q ; pp = &q->next, q = q->next)
+ if (q->info.si_signo == sig)
+ break;
+ if (q) {
+ if ((*pp = q->next) == NULL)
+ t->sigqueue_tail = pp;
+ kmem_cache_free(signal_queue_cachep,q);
+ atomic_dec(&nr_queued_signals);
+ }
+ return 1;
+}
+
+/*
* Determine whether a signal should be posted or not.
*
* Signals with SIG_IGN can be ignored, except for the
@@ -273,18 +311,16 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
if (t->state == TASK_STOPPED)
wake_up_process(t);
t->exit_code = 0;
- sigdelsetmask(&t->signal, (sigmask(SIGSTOP)|sigmask(SIGTSTP)|
- sigmask(SIGTTOU)|sigmask(SIGTTIN)));
- /* Inflict this corner case with recalculations, not mainline */
- recalc_sigpending(t);
+ if (rm_sig_from_queue(SIGSTOP, t) || rm_sig_from_queue(SIGTSTP, t) ||
+ rm_sig_from_queue(SIGTTOU, t) || rm_sig_from_queue(SIGTTIN, t))
+ recalc_sigpending(t);
break;
case SIGSTOP: case SIGTSTP:
case SIGTTIN: case SIGTTOU:
/* If we're stopping again, cancel SIGCONT */
- sigdelset(&t->signal, SIGCONT);
- /* Inflict this corner case with recalculations, not mainline */
- recalc_sigpending(t);
+ if (rm_sig_from_queue(SIGCONT, t))
+ recalc_sigpending(t);
break;
}
@@ -338,8 +374,12 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
q->info = *info;
break;
}
- } else {
- /* Queue overflow, we have to abort. */
+ } else if (sig >= SIGRTMIN && info && (unsigned long)info != 1
+ && info->si_code < 0) {
+ /*
+ * Queue overflow, abort. We may abort if the signal was rt
+ * and sent by user using something other than kill().
+ */
ret = -EAGAIN;
goto out;
}
@@ -406,7 +446,7 @@ force_sig_info(int sig, struct siginfo *info, struct task_struct *t)
}
/*
- * kill_pg() sends a signal to a process group: this is what the tty
+ * kill_pg_info() sends a signal to a process group: this is what the tty
* control characters do (^C, ^Z etc)
*/
@@ -437,7 +477,7 @@ kill_pg_info(int sig, struct siginfo *info, pid_t pgrp)
}
/*
- * kill_sl() sends a signal to the session leader: this is used
+ * kill_sl_info() sends a signal to the session leader: this is used
* to send SIGHUP to the controlling process of a terminal when
* the connection is lost.
*/
@@ -484,7 +524,7 @@ kill_proc_info(int sig, struct siginfo *info, pid_t pid)
}
/*
- * kill_something() interprets pid in interesting ways just like kill(2).
+ * kill_something_info() interprets pid in interesting ways just like kill(2).
*
* POSIX specifies that kill(-1,sig) is unspecified, but what we have
* is probably wrong. Should make it like BSD or SYSV.