Currently sigqueue_free() removes sigqueue from list, but doesn't cancel the pending signal. This is not consistent, the task should either receive the "full" signal along with siginfo_t, or it shouldn't see the signal at all. Change sigqueue_free() to clear SIGQUEUE_PREALLOC but leave sigqueue on list if it is queued. Note: I am not sure we shouldn't do the opposite, free sigqueue + cancel the pending signal, but this needs some ugly changes. Perhaps we should reconsider this change later. See also http://bugzilla.kernel.org/show_bug.cgi?id=10460 Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru> --- 25/kernel/signal.c~2_SF_DONT_REMOVE 2008-05-03 18:27:03.000000000 +0400 +++ 25/kernel/signal.c 2008-05-03 19:12:36.000000000 +0400 @@ -1240,18 +1240,22 @@ void sigqueue_free(struct sigqueue *q) BUG_ON(!(q->flags & SIGQUEUE_PREALLOC)); /* - * If the signal is still pending remove it from the - * pending queue. We must hold ->siglock while testing - * q->list to serialize with collect_signal() or with + * We must hold ->siglock while testing q->list + * to serialize with collect_signal() or with * __exit_signal()->flush_sigqueue(). */ spin_lock_irqsave(lock, flags); + /* + * If it is queued it will be freed when dequeued, + * like the "regular" sigqueue. + */ + q->flags &= ~SIGQUEUE_PREALLOC; if (!list_empty(&q->list)) - list_del_init(&q->list); + q = NULL; spin_unlock_irqrestore(lock, flags); - q->flags &= ~SIGQUEUE_PREALLOC; - __sigqueue_free(q); + if (q) + __sigqueue_free(q); } int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group) --
You know what, I think there might be an even simple solution. How about just setting a bit saying it is canceled - and nothing more. Then, the dequeue logic can be just taught to ignore those things. Doesn't that sound like the simple way to cancel signals? Make collect_signal() just do a "return 0" if the signal has been flushed.. Linus --
Yes, good idea, I'll send the patch in a minute. Unless I missed something again, "nothing more" can't work. We still need this patch (re-sended). We still need to free sigqueue if it is not queued, and we must not dequeue it if it is queued - otherwise we will free it along with the new "canceled" bit. Oleg. --
I see the light! Will return on May 10. (Damn, you have proved I'm stupid twice on the same issue! OK, OK, thanks ;) Oleg. --
In that case perhaps we can do something like (uncompiled, just for illustration)
patch below.
While I don't know what is the "right" behaviour, I hate this patch because
it "looks ugly" (even if correct).
Oleg.
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1709,7 +1709,7 @@ extern int send_sig(int, struct task_str
extern void zap_other_threads(struct task_struct *p);
extern int kill_proc(pid_t, int, int);
extern struct sigqueue *sigqueue_alloc(void);
-extern void sigqueue_free(struct sigqueue *);
+extern void sigqueue_free(struct sigqueue *, struct sigpending *pending);
extern int send_sigqueue(struct sigqueue *, struct task_struct *, int group);
extern int do_sigaction(int, struct k_sigaction *, struct k_sigaction *);
extern int do_sigaltstack(const stack_t __user *, stack_t __user *, unsigned long);
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1233,7 +1233,24 @@ struct sigqueue *sigqueue_alloc(void)
return(q);
}
-void sigqueue_free(struct sigqueue *q)
+static void sigqueue_cancel(struct sigqueue *q, struct sigpending *pending)
+{
+ int sig;
+
+ list_del_init(&q->list);
+
+ sig = q->info.si_signo;
+ if (sig >= SIGRTMIN) {
+ list_for_each_entry(q, &pending->list, list)
+ if (q->info.si_signo == sig)
+ return;
+ }
+
+ sigdelset(&pending->signal, sig);
+}
+
+
+void sigqueue_free(struct sigqueue *q, struct sigpending *pending)
{
unsigned long flags;
spinlock_t *lock = &current->sighand->siglock;
@@ -1245,17 +1262,12 @@ void sigqueue_free(struct sigqueue *q)
* __exit_signal()->flush_sigqueue().
*/
spin_lock_irqsave(lock, flags);
- /*
- * If it is queued it will be freed when dequeued,
- * like the "regular" sigqueue.
- */
- q->flags &= ~SIGQUEUE_PREALLOC;
if (!list_empty(&q->list))
- q = NULL;
+ sigqueue_cancel(q, pending);
spin_unlock_irqrestore(lock, flags);
- if (q)
- __sigqueue_free(q);
+ q->flags &= ~SIGQUEUE_PREALLOC;
+ ...
| Greg Kroah-Hartman | [PATCH 009/196] Chinese: add translation of sparse.txt |
| Artem Bityutskiy | [PATCH take 2 06/28] UBIFS: add journal replay |
| Luck, Tony | RE: [Ksummit-2008-discuss] Fixing the Kernel Janitors project |
| FUJITA Tomonori | Re: Integration of SCST in the mainstream Linux kernel |
git: | |
| ir0s | Local branch ahead of tracked remote branch but git push claims everything up-to-d... |
| Matthieu Moy | git push to a non-bare repository |
| Johannes Schindelin | Re: VCS comparison table |
| Rocco Rutte | mercurial to git |
| Sunnz | radeon driver in -current Xorg 7.2? |
| Neko | reliable, dd over simple ip network |
| GVG GVG | ssh_exchange_identification: Connection closed by remote host |
| Siju George | This is what Linus Torvalds calls openBSD crowd |
| David Miller | [GIT]: Networking |
| Inaky Perez-Gonzalez | [PATCH 00/39] merge request for WiMAX kernel stack and i2400m driver |
| Jarek Poplawski | [PATCH] pkt_sched: Destroy gen estimators under rtnl_lock(). |
| Evgeniy Polyakov | Re: [bug, netconsole, SLUB] BUG skbuff_head_cache: Poison overwritten |
