Re: [PATCH] file: kill unnecessary timer in fdtable_defer

From: Tejun Heo
Date: Mon Aug 21 2006 - 01:21:17 EST


On Mon, Aug 21, 2006 at 10:02:57AM +0530, Dipankar Sarma wrote:
> On Sun, Aug 20, 2006 at 10:15:42PM +0900, Tejun Heo wrote:
> > free_fdtable_rc() schedules timer to reschedule fddef->wq if
> > schedule_work() on it returns 0. However, schedule_work() guarantees
> > that the target work is executed at least once after the scheduling
> > regardless of its return value. 0 return simply means that the work
> > was already pending and thus no further action was required.
>
> Hmm.. Is this really true ? IIRC, schedule_work() checks pending
> work based on bit ops on work->pending and clear_bit() is not
> a memory barrier.

Those bitops are not memory barriers but they can define order between
them alright. Once the execution order is correct, the rest of
synchronization is the caller's responsbility. In fddef's case, it's
achieved via fddef->lock.

> So, if I see work->pending = 1 in free_fdtable_work(), how do I know
> that the work function is already executing and missed the new work
> that I had queued ?

This is classical edge-triggered event handling where each event
doesn't require separate handling. The producer produces one or more
items at a time and the consumer consumes the whole queue on
invocation.

For example, when Pn indicates producing of item n and C indicates
consuming. The seqeunce "P0 C P1 C P2 C" and "P0 P1 P2 C" are
effectively identical, so all that's required for correct operation
(that is, full queue consumption) is that the consumer is run at least
once after producing of the last item.

In workqueue, this is guaranteed by

1. If pending bit is set, the work is guaranteed to be executed in
some future - it's on timer or queue.

2. The queuer sets the pending bit *after* producing a job to be
done.

3. The worker clears the pending *before* executing the job.

I sometimes find it easier to understand with a diagram which looks
like the following. Time flows from top to bottom.

Queuer Worker

-------------
| produce job |
| | <--- clr pending --->
------------- |
| v
v --------------
<--- set pending ---> | consume jobs |
| |
--------------

Now move the queuer and worker up and down in your mind. If 'set
pending' is higher than clr pending 'consume job' is guaranteed to see
the job queuer has produced whether pending is set or clear
beforehand. If 'set pending' is lower than 'clr pending', it is
guaranteed to set pending and schedule worker. The workqueue is
straight-forward expansion where there are N queuers and a repeating
consumer.

--
tejun
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/