* [PATCH 2/4] posix timers: sigqueue_free: don't free sigqueue if it is queued
@ 2008-05-03 17:35 Oleg Nesterov
2008-05-03 17:43 ` Oleg Nesterov
2008-05-03 17:51 ` Linus Torvalds
0 siblings, 2 replies; 5+ messages in thread
From: Oleg Nesterov @ 2008-05-03 17:35 UTC (permalink / raw)
To: Andrew Morton
Cc: Austin Clements, Ingo Molnar, john stultz, Linus Torvalds,
Michael Kerrisk, Roland McGrath, Thomas Gleixner, linux-kernel
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)
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/4] posix timers: sigqueue_free: don't free sigqueue if it is queued
2008-05-03 17:35 [PATCH 2/4] posix timers: sigqueue_free: don't free sigqueue if it is queued Oleg Nesterov
@ 2008-05-03 17:43 ` Oleg Nesterov
2008-05-03 17:51 ` Linus Torvalds
1 sibling, 0 replies; 5+ messages in thread
From: Oleg Nesterov @ 2008-05-03 17:43 UTC (permalink / raw)
To: Andrew Morton
Cc: Austin Clements, Ingo Molnar, john stultz, Linus Torvalds,
Michael Kerrisk, Roland McGrath, Thomas Gleixner, linux-kernel
On 05/03, Oleg Nesterov wrote:
>
> 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
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 = ¤t->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;
+ __sigqueue_free(q);
}
int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group)
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -449,7 +449,6 @@ static void release_posix_timer(struct k
idr_remove(&posix_timers_id, tmr->it_id);
spin_unlock_irqrestore(&idr_lock, flags);
}
- sigqueue_free(tmr->sigq);
kmem_cache_free(posix_timers_cache, tmr);
}
@@ -828,6 +827,27 @@ static inline int timer_delete_hook(stru
return CLOCK_DISPATCH(timer->it_clock, timer_del, (timer));
}
+static void __timer_delete(struct k_itimer *timer, unsigned long flags)
+{
+ struct sigpending *pending;
+
+ pending = ¤t->signal->shared_pending;
+ if (timer->it_sigev_notify == (SIGEV_SIGNAL|SIGEV_THREAD_ID)) {
+ pending = &timer->it_process->pending;
+ put_task_struct(timer->it_process);
+ }
+ /*
+ * This keeps any tasks waiting on the spin lock from thinking
+ * they got something (see the lock code above).
+ */
+ timer->it_process = NULL;
+ unlock_timer(timer, flags);
+
+ /* Note that "pending" can point to the freed memory */
+ sigqueue_free(timer->sigq, pending);
+ release_posix_timer(timer, IT_ID_SET);
+}
+
/* Delete a POSIX.1b interval timer. */
asmlinkage long
sys_timer_delete(timer_t timer_id)
@@ -848,16 +868,8 @@ retry_delete:
spin_lock(¤t->sighand->siglock);
list_del(&timer->list);
spin_unlock(¤t->sighand->siglock);
- /*
- * This keeps any tasks waiting on the spin lock from thinking
- * they got something (see the lock code above).
- */
- if (timer->it_sigev_notify == (SIGEV_SIGNAL|SIGEV_THREAD_ID))
- put_task_struct(timer->it_process);
- timer->it_process = NULL;
- unlock_timer(timer, flags);
- release_posix_timer(timer, IT_ID_SET);
+ __timer_delete(timer, flags);
return 0;
}
@@ -876,16 +888,8 @@ retry_delete:
goto retry_delete;
}
list_del(&timer->list);
- /*
- * This keeps any tasks waiting on the spin lock from thinking
- * they got something (see the lock code above).
- */
- if (timer->it_sigev_notify == (SIGEV_SIGNAL|SIGEV_THREAD_ID))
- put_task_struct(timer->it_process);
- timer->it_process = NULL;
- unlock_timer(timer, flags);
- release_posix_timer(timer, IT_ID_SET);
+ __timer_delete(timer, flags);
}
/*
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/4] posix timers: sigqueue_free: don't free sigqueue if it is queued
2008-05-03 17:35 [PATCH 2/4] posix timers: sigqueue_free: don't free sigqueue if it is queued Oleg Nesterov
2008-05-03 17:43 ` Oleg Nesterov
@ 2008-05-03 17:51 ` Linus Torvalds
2008-05-03 19:19 ` Oleg Nesterov
2008-05-17 15:13 ` Oleg Nesterov
1 sibling, 2 replies; 5+ messages in thread
From: Linus Torvalds @ 2008-05-03 17:51 UTC (permalink / raw)
To: Oleg Nesterov
Cc: Andrew Morton, Austin Clements, Ingo Molnar, john stultz,
Michael Kerrisk, Roland McGrath, Thomas Gleixner, linux-kernel
On Sat, 3 May 2008, Oleg Nesterov wrote:
>
> 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
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
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/4] posix timers: sigqueue_free: don't free sigqueue if it is queued
2008-05-03 17:51 ` Linus Torvalds
@ 2008-05-03 19:19 ` Oleg Nesterov
2008-05-17 15:13 ` Oleg Nesterov
1 sibling, 0 replies; 5+ messages in thread
From: Oleg Nesterov @ 2008-05-03 19:19 UTC (permalink / raw)
To: Linus Torvalds
Cc: Andrew Morton, Austin Clements, Ingo Molnar, john stultz,
Michael Kerrisk, Roland McGrath, Thomas Gleixner, linux-kernel
On 05/03, Linus Torvalds wrote:
>
> On Sat, 3 May 2008, Oleg Nesterov wrote:
> >
> > 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
>
> You know what, I think there might be an even simple solution.
>
> How about just setting a bit saying it is canceled
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.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/4] posix timers: sigqueue_free: don't free sigqueue if it is queued
2008-05-03 17:51 ` Linus Torvalds
2008-05-03 19:19 ` Oleg Nesterov
@ 2008-05-17 15:13 ` Oleg Nesterov
1 sibling, 0 replies; 5+ messages in thread
From: Oleg Nesterov @ 2008-05-17 15:13 UTC (permalink / raw)
To: Linus Torvalds
Cc: Andrew Morton, Austin Clements, Ingo Molnar, john stultz,
Michael Kerrisk, Roland McGrath, Thomas Gleixner, linux-kernel
On 05/03, Linus Torvalds wrote:
>
> On Sat, 3 May 2008, Oleg Nesterov wrote:
> >
> > 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
>
> You know what, I think there might be an even simple solution.
>
> How about just setting a bit saying it is canceled
Yes, good idea, I'll send the patch in a minute.
But now I see I didn't read your message to the end,
> - and nothing more.
> Then, the dequeue logic can be just taught to ignore those things.
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.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2008-05-17 15:15 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-05-03 17:35 [PATCH 2/4] posix timers: sigqueue_free: don't free sigqueue if it is queued Oleg Nesterov
2008-05-03 17:43 ` Oleg Nesterov
2008-05-03 17:51 ` Linus Torvalds
2008-05-03 19:19 ` Oleg Nesterov
2008-05-17 15:13 ` Oleg Nesterov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox