LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH] cancel_delayed_work: use del_timer() instead of del_timer_sync()
@ 2007-04-24 21:50 Oleg Nesterov
2007-04-25 10:04 ` David Howells
2007-04-25 13:02 ` Jarek Poplawski
0 siblings, 2 replies; 8+ messages in thread
From: Oleg Nesterov @ 2007-04-24 21:50 UTC (permalink / raw)
To: Andrew Morton
Cc: David Howells, David Miller, Ingo Molnar, Jarek Poplawski, linux-kernel
del_timer_sync() buys nothing for cancel_delayed_work(), but it is less
efficient since it locks the timer unconditionally, and may wait for the
completion of the delayed_work_timer_fn().
cancel_delayed_work() == 0 means:
before this patch:
work->func may still be running or queued
after this patch:
work->func may still be running or queued, or
delayed_work_timer_fn->__queue_work() in progress.
The latter doesn't differ from the caller's POV,
delayed_work_timer_fn() is called with _PENDING
bit set.
cancel_delayed_work() == 1 with this patch adds a new possibility:
delayed_work->work was cancelled, but delayed_work_timer_fn
is still running (this is only possible for the re-arming
works on single-threaded workqueue).
In this case the timer was re-started by work->func(), nobody
else can do this. This in turn means that delayed_work_timer_fn
has already passed __queue_work() (and wont't touch delayed_work)
because nobody else can queue delayed_work->work.
Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
--- OLD/include/linux/workqueue.h~2_CDW 2007-04-05 12:20:35.000000000 +0400
+++ OLD/include/linux/workqueue.h 2007-04-25 01:48:24.000000000 +0400
@@ -152,14 +152,15 @@ extern void cancel_work_sync(struct work
/*
* Kill off a pending schedule_delayed_work(). Note that the work callback
- * function may still be running on return from cancel_delayed_work(). Run
- * flush_workqueue() or cancel_work_sync() to wait on it.
+ * function may still be running on return from cancel_delayed_work(), unless
+ * it returns 1 and the work doesn't re-arm itself. Run flush_workqueue() or
+ * cancel_work_sync() to wait on it.
*/
static inline int cancel_delayed_work(struct delayed_work *work)
{
int ret;
- ret = del_timer_sync(&work->timer);
+ ret = del_timer(&work->timer);
if (ret)
work_clear_pending(&work->work);
return ret;
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] cancel_delayed_work: use del_timer() instead of del_timer_sync()
2007-04-24 21:50 [PATCH] cancel_delayed_work: use del_timer() instead of del_timer_sync() Oleg Nesterov
@ 2007-04-25 10:04 ` David Howells
2007-04-25 13:02 ` Jarek Poplawski
1 sibling, 0 replies; 8+ messages in thread
From: David Howells @ 2007-04-25 10:04 UTC (permalink / raw)
To: Oleg Nesterov
Cc: Andrew Morton, David Miller, Ingo Molnar, Jarek Poplawski, linux-kernel
Oleg Nesterov <oleg@tv-sign.ru> wrote:
> del_timer_sync() buys nothing for cancel_delayed_work(), but it is less
> efficient since it locks the timer unconditionally, and may wait for the
> completion of the delayed_work_timer_fn().
Okay, this patch seems to work for me, though I'm not using any of the other
related patches that are in the -mm tree (I modified this patch to compile
directly on top of Linus's vanilla tree).
Acked-By: David Howells <dhowells@redhat.com>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] cancel_delayed_work: use del_timer() instead of del_timer_sync()
2007-04-25 13:02 ` Jarek Poplawski
@ 2007-04-25 12:52 ` Oleg Nesterov
2007-04-26 14:29 ` Jarek Poplawski
0 siblings, 1 reply; 8+ messages in thread
From: Oleg Nesterov @ 2007-04-25 12:52 UTC (permalink / raw)
To: Jarek Poplawski
Cc: Andrew Morton, David Howells, David Miller, Ingo Molnar, linux-kernel
On 04/25, Jarek Poplawski wrote:
>
> On Wed, Apr 25, 2007 at 01:50:34AM +0400, Oleg Nesterov wrote:
> > del_timer_sync() buys nothing for cancel_delayed_work(), but it is less
> > efficient since it locks the timer unconditionally, and may wait for the
> > completion of the delayed_work_timer_fn().
>
> I'm not sure what is the main aim of this patch.
optimization
> It seems this
> change cannot do any harm, but anyway it could change a few
> things, e.g. with current version of cancel_rearming_delayed_work
> some flush_workqueue could be done needlessly, before the work
> is queued from timer.
I don't think so... Could you clarify?
> It's not a big deal here, but if anybody
> did something like this without loop - it could matter.
>
> So, probably a lot of current code should be checked, before
> applying and I doubt the gain is worth of this. Maybe, for
> safety, make this with new name as an alternative and
> deprecate the current version?
This change should not make any visible difference for the callers,
otherwise it is buggy.
Oleg.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] cancel_delayed_work: use del_timer() instead of del_timer_sync()
2007-04-24 21:50 [PATCH] cancel_delayed_work: use del_timer() instead of del_timer_sync() Oleg Nesterov
2007-04-25 10:04 ` David Howells
@ 2007-04-25 13:02 ` Jarek Poplawski
2007-04-25 12:52 ` Oleg Nesterov
1 sibling, 1 reply; 8+ messages in thread
From: Jarek Poplawski @ 2007-04-25 13:02 UTC (permalink / raw)
To: Oleg Nesterov
Cc: Andrew Morton, David Howells, David Miller, Ingo Molnar, linux-kernel
On Wed, Apr 25, 2007 at 01:50:34AM +0400, Oleg Nesterov wrote:
> del_timer_sync() buys nothing for cancel_delayed_work(), but it is less
> efficient since it locks the timer unconditionally, and may wait for the
> completion of the delayed_work_timer_fn().
I'm not sure what is the main aim of this patch. It seems this
change cannot do any harm, but anyway it could change a few
things, e.g. with current version of cancel_rearming_delayed_work
some flush_workqueue could be done needlessly, before the work
is queued from timer. It's not a big deal here, but if anybody
did something like this without loop - it could matter.
So, probably a lot of current code should be checked, before
applying and I doubt the gain is worth of this. Maybe, for
safety, make this with new name as an alternative and
deprecate the current version?
Regards,
Jarek P.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] cancel_delayed_work: use del_timer() instead of del_timer_sync()
2007-04-25 12:52 ` Oleg Nesterov
@ 2007-04-26 14:29 ` Jarek Poplawski
2007-04-26 15:29 ` Oleg Nesterov
0 siblings, 1 reply; 8+ messages in thread
From: Jarek Poplawski @ 2007-04-26 14:29 UTC (permalink / raw)
To: Oleg Nesterov
Cc: Andrew Morton, David Howells, David Miller, Ingo Molnar, linux-kernel
On Wed, Apr 25, 2007 at 04:52:14PM +0400, Oleg Nesterov wrote:
> On 04/25, Jarek Poplawski wrote:
> >
> > On Wed, Apr 25, 2007 at 01:50:34AM +0400, Oleg Nesterov wrote:
> > > del_timer_sync() buys nothing for cancel_delayed_work(), but it is less
> > > efficient since it locks the timer unconditionally, and may wait for the
> > > completion of the delayed_work_timer_fn().
> >
> > I'm not sure what is the main aim of this patch.
>
> optimization
>
> > It seems this
> > change cannot do any harm, but anyway it could change a few
> > things, e.g. with current version of cancel_rearming_delayed_work
> > some flush_workqueue could be done needlessly, before the work
> > is queued from timer.
>
> I don't think so... Could you clarify?
With a code like:
if (!cancel_delayed_work(dwork))
flush_workqueue(wq);
if cancel_ returns 0, and there is _queue_work in progress,
flush_ will be done once, after this work is queued.
After the patch, and the same situation flush_ also runs
one time, but maybe without the work in a queue.
So, if there is no more loops, there could be difference,
and even if very unprobable, something could stop working
after such change.
>
> > It's not a big deal here, but if anybody
> > did something like this without loop - it could matter.
> >
> > So, probably a lot of current code should be checked, before
> > applying and I doubt the gain is worth of this. Maybe, for
> > safety, make this with new name as an alternative and
> > deprecate the current version?
>
> This change should not make any visible difference for the callers,
> otherwise it is buggy.
IMHO, there is the same visible difference,
as between del_timer and del_timer_sync.
Regards,
Jarek P.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] cancel_delayed_work: use del_timer() instead of del_timer_sync()
2007-04-26 14:29 ` Jarek Poplawski
@ 2007-04-26 15:29 ` Oleg Nesterov
2007-04-27 6:15 ` Jarek Poplawski
0 siblings, 1 reply; 8+ messages in thread
From: Oleg Nesterov @ 2007-04-26 15:29 UTC (permalink / raw)
To: Jarek Poplawski
Cc: Andrew Morton, David Howells, David Miller, Ingo Molnar, linux-kernel
On 04/26, Jarek Poplawski wrote:
>
> On Wed, Apr 25, 2007 at 04:52:14PM +0400, Oleg Nesterov wrote:
> >
> > > It seems this
> > > change cannot do any harm, but anyway it could change a few
> > > things, e.g. with current version of cancel_rearming_delayed_work
> > > some flush_workqueue could be done needlessly, before the work
> > > is queued from timer.
> >
> > I don't think so... Could you clarify?
>
> With a code like:
>
> if (!cancel_delayed_work(dwork))
> flush_workqueue(wq);
>
> if cancel_ returns 0, and there is _queue_work in progress,
> flush_ will be done once, after this work is queued.
>
> After the patch, and the same situation flush_ also runs
> one time, but maybe without the work in a queue.
First, this is very unlikely event, and the behaviour is correct,
do you agree?
Even in this case, it is very unlikely that flush_cpu_workqueue()
will take cwq->lock before extremely short delayed_work_timer_fn.
Even if it does, work->func() likely will be completed when the
caller of flush_workqueue() will be woken by run_workquue() and
gets CPU.
Please also look at http://marc.info/?t=117699337200022&r=1
> > > It's not a big deal here, but if anybody
> > > did something like this without loop - it could matter.
> > >
> > > So, probably a lot of current code should be checked, before
> > > applying and I doubt the gain is worth of this. Maybe, for
> > > safety, make this with new name as an alternative and
> > > deprecate the current version?
> >
> > This change should not make any visible difference for the callers,
> > otherwise it is buggy.
>
> IMHO, there is the same visible difference,
> as between del_timer and del_timer_sync.
Jarek, please, could you be more explicite ? del_timer() and
del_timer_sync() are different in many ways. What exactly will
impact the user of cancel_delaye_work ?
Oleg.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] cancel_delayed_work: use del_timer() instead of del_timer_sync()
2007-04-26 15:29 ` Oleg Nesterov
@ 2007-04-27 6:15 ` Jarek Poplawski
2007-04-27 7:23 ` Oleg Nesterov
0 siblings, 1 reply; 8+ messages in thread
From: Jarek Poplawski @ 2007-04-27 6:15 UTC (permalink / raw)
To: Oleg Nesterov
Cc: Andrew Morton, David Howells, David Miller, Ingo Molnar, linux-kernel
On Thu, Apr 26, 2007 at 07:29:53PM +0400, Oleg Nesterov wrote:
> On 04/26, Jarek Poplawski wrote:
...
> > > This change should not make any visible difference for the callers,
> > > otherwise it is buggy.
> >
> > IMHO, there is the same visible difference,
> > as between del_timer and del_timer_sync.
>
> Jarek, please, could you be more explicite ? del_timer() and
> del_timer_sync() are different in many ways. What exactly will
> impact the user of cancel_delaye_work ?
OK, I changed my mind. Now, I think it's very probable
this should matter...
According to workqueue.h:
> /*
> * Kill off a pending schedule_delayed_work(). Note that the work callback
> * function may still be running on return from cancel_delayed_work(). Run
> * flush_workqueue() or cancel_work_sync() to wait on it.
> */
> static inline int cancel_delayed_work(struct delayed_work *work)
So, we can do something like this:
cancel_delayed_work(dwork);
flush_workqueue(wq);
kfree(some_obj_used_by_dwork_func);
And this is enough to work with not rearming work.
But no more after this patch...
So, I think, your proposal should be alternative version,
and current version should stay, so we have a choice.
Just like del_timer and del_timer_sync.
Jarek P.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] cancel_delayed_work: use del_timer() instead of del_timer_sync()
2007-04-27 6:15 ` Jarek Poplawski
@ 2007-04-27 7:23 ` Oleg Nesterov
0 siblings, 0 replies; 8+ messages in thread
From: Oleg Nesterov @ 2007-04-27 7:23 UTC (permalink / raw)
To: Jarek Poplawski
Cc: Andrew Morton, David Howells, David Miller, Ingo Molnar, linux-kernel
On 04/27, Jarek Poplawski wrote:
>
> According to workqueue.h:
> > /*
> > * Kill off a pending schedule_delayed_work(). Note that the work callback
> > * function may still be running on return from cancel_delayed_work(). Run
> > * flush_workqueue() or cancel_work_sync() to wait on it.
> > */
> > static inline int cancel_delayed_work(struct delayed_work *work)
>
> So, we can do something like this:
>
> cancel_delayed_work(dwork);
> flush_workqueue(wq);
> kfree(some_obj_used_by_dwork_func);
>
> And this is enough to work with not rearming work.
>
> But no more after this patch...
Yes, you are right, and so this patch is wrong.
This is even documented in the changelog, with this change cancel_delayed_work()
may return while the queueing is in progress. However, in that case we can not
rely on flush_workqueue/cancel_work_sync.
Thanks a lot!
Oleg.
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2007-04-27 7:23 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-04-24 21:50 [PATCH] cancel_delayed_work: use del_timer() instead of del_timer_sync() Oleg Nesterov
2007-04-25 10:04 ` David Howells
2007-04-25 13:02 ` Jarek Poplawski
2007-04-25 12:52 ` Oleg Nesterov
2007-04-26 14:29 ` Jarek Poplawski
2007-04-26 15:29 ` Oleg Nesterov
2007-04-27 6:15 ` Jarek Poplawski
2007-04-27 7:23 ` Oleg Nesterov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).