diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-03-27 23:54:12 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-03-27 23:54:12 +0000 |
commit | d3e71cb08747743fce908122bab08b479eb403a5 (patch) | |
tree | cbec6948fdbdee9af81cf3ecfb504070d2745d7b /kernel/signal.c | |
parent | fe7ff1706e323d0e5ed83972960a1ecc1ee538b3 (diff) |
Merge with Linux 2.3.99-pre3.
Diffstat (limited to 'kernel/signal.c')
-rw-r--r-- | kernel/signal.c | 94 |
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(¤t->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. |