aboutsummaryrefslogtreecommitdiff
path: root/kernel/signal.c
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2007-09-14 01:24:25 +1000
committerPaul Mackerras <paulus@samba.org>2007-09-14 01:24:25 +1000
commitb2315372eac9cd9f622c32a93e323cf6f0f03462 (patch)
tree9e1faa7cdcddf5d90bec4fb9523742d4cce699a1 /kernel/signal.c
parent5326152fa182b0a16e4abf913ce403e3c7ab53b7 (diff)
parentc87ce65868bbf9bbea9c3f112ff8315302daf8f2 (diff)
Merge branch 'linux-2.6' into for-2.6.24
Diffstat (limited to 'kernel/signal.c')
-rw-r--r--kernel/signal.c19
1 files changed, 9 insertions, 10 deletions
diff --git a/kernel/signal.c b/kernel/signal.c
index ad63109e413..3169bed0b4d 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1300,20 +1300,19 @@ struct sigqueue *sigqueue_alloc(void)
void sigqueue_free(struct sigqueue *q)
{
unsigned long flags;
+ spinlock_t *lock = &current->sighand->siglock;
+
BUG_ON(!(q->flags & SIGQUEUE_PREALLOC));
/*
* If the signal is still pending remove it from the
- * pending queue.
+ * pending queue. We must hold ->siglock while testing
+ * q->list to serialize with collect_signal().
*/
- if (unlikely(!list_empty(&q->list))) {
- spinlock_t *lock = &current->sighand->siglock;
- read_lock(&tasklist_lock);
- spin_lock_irqsave(lock, flags);
- if (!list_empty(&q->list))
- list_del_init(&q->list);
- spin_unlock_irqrestore(lock, flags);
- read_unlock(&tasklist_lock);
- }
+ spin_lock_irqsave(lock, flags);
+ if (!list_empty(&q->list))
+ list_del_init(&q->list);
+ spin_unlock_irqrestore(lock, flags);
+
q->flags &= ~SIGQUEUE_PREALLOC;
__sigqueue_free(q);
}