diff options
| author | Tejun Heo <tj@kernel.org> | 2010-09-16 04:42:16 -0400 | 
|---|---|---|
| committer | Tejun Heo <tj@kernel.org> | 2010-09-19 11:51:05 -0400 | 
| commit | baf59022c37d43f202e62d5130e4bac5e825b426 (patch) | |
| tree | 43eea7aac112b2ee07b195e00bce4b14465d1183 | |
| parent | 401a8d048eadfbe1b1c1bf53d3b614fcc894c61a (diff) | |
workqueue: factor out start_flush_work()
Factor out start_flush_work() from flush_work().  start_flush_work()
has @wait_executing argument which controls whether the barrier is
queued only if the work is pending or also if executing.  As
flush_work() needs to wait for execution too, it uses %true.
This commit doesn't cause any behavior difference.  start_flush_work()
will be used to implement flush_work_sync().
Signed-off-by: Tejun Heo <tj@kernel.org>
| -rw-r--r-- | kernel/workqueue.c | 64 | 
1 files changed, 37 insertions, 27 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 1240b9d94b03..33d31d768706 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c  | |||
| @@ -2326,35 +2326,17 @@ out_unlock: | |||
| 2326 | } | 2326 | } | 
| 2327 | EXPORT_SYMBOL_GPL(flush_workqueue); | 2327 | EXPORT_SYMBOL_GPL(flush_workqueue); | 
| 2328 | 2328 | ||
| 2329 | /** | 2329 | static bool start_flush_work(struct work_struct *work, struct wq_barrier *barr, | 
| 2330 | * flush_work - wait for a work to finish executing the last queueing instance | 2330 | bool wait_executing) | 
| 2331 | * @work: the work to flush | ||
| 2332 | * | ||
| 2333 | * Wait until @work has finished execution. This function considers | ||
| 2334 | * only the last queueing instance of @work. If @work has been | ||
| 2335 | * enqueued across different CPUs on a non-reentrant workqueue or on | ||
| 2336 | * multiple workqueues, @work might still be executing on return on | ||
| 2337 | * some of the CPUs from earlier queueing. | ||
| 2338 | * | ||
| 2339 | * If @work was queued only on a non-reentrant, ordered or unbound | ||
| 2340 | * workqueue, @work is guaranteed to be idle on return if it hasn't | ||
| 2341 | * been requeued since flush started. | ||
| 2342 | * | ||
| 2343 | * RETURNS: | ||
| 2344 | * %true if flush_work() waited for the work to finish execution, | ||
| 2345 | * %false if it was already idle. | ||
| 2346 | */ | ||
| 2347 | bool flush_work(struct work_struct *work) | ||
| 2348 | { | 2331 | { | 
| 2349 | struct worker *worker = NULL; | 2332 | struct worker *worker = NULL; | 
| 2350 | struct global_cwq *gcwq; | 2333 | struct global_cwq *gcwq; | 
| 2351 | struct cpu_workqueue_struct *cwq; | 2334 | struct cpu_workqueue_struct *cwq; | 
| 2352 | struct wq_barrier barr; | ||
| 2353 | 2335 | ||
| 2354 | might_sleep(); | 2336 | might_sleep(); | 
| 2355 | gcwq = get_work_gcwq(work); | 2337 | gcwq = get_work_gcwq(work); | 
| 2356 | if (!gcwq) | 2338 | if (!gcwq) | 
| 2357 | return 0; | 2339 | return false; | 
| 2358 | 2340 | ||
| 2359 | spin_lock_irq(&gcwq->lock); | 2341 | spin_lock_irq(&gcwq->lock); | 
| 2360 | if (!list_empty(&work->entry)) { | 2342 | if (!list_empty(&work->entry)) { | 
| @@ -2367,26 +2349,54 @@ bool flush_work(struct work_struct *work) | |||
| 2367 | cwq = get_work_cwq(work); | 2349 | cwq = get_work_cwq(work); | 
| 2368 | if (unlikely(!cwq || gcwq != cwq->gcwq)) | 2350 | if (unlikely(!cwq || gcwq != cwq->gcwq)) | 
| 2369 | goto already_gone; | 2351 | goto already_gone; | 
| 2370 | } else { | 2352 | } else if (wait_executing) { | 
| 2371 | worker = find_worker_executing_work(gcwq, work); | 2353 | worker = find_worker_executing_work(gcwq, work); | 
| 2372 | if (!worker) | 2354 | if (!worker) | 
| 2373 | goto already_gone; | 2355 | goto already_gone; | 
| 2374 | cwq = worker->current_cwq; | 2356 | cwq = worker->current_cwq; | 
| 2375 | } | 2357 | } else | 
| 2358 | goto already_gone; | ||
| 2376 | 2359 | ||
| 2377 | insert_wq_barrier(cwq, &barr, work, worker); | 2360 | insert_wq_barrier(cwq, barr, work, worker); | 
| 2378 | spin_unlock_irq(&gcwq->lock); | 2361 | spin_unlock_irq(&gcwq->lock); | 
| 2379 | 2362 | ||
| 2380 | lock_map_acquire(&cwq->wq->lockdep_map); | 2363 | lock_map_acquire(&cwq->wq->lockdep_map); | 
| 2381 | lock_map_release(&cwq->wq->lockdep_map); | 2364 | lock_map_release(&cwq->wq->lockdep_map); | 
| 2382 | |||
| 2383 | wait_for_completion(&barr.done); | ||
| 2384 | destroy_work_on_stack(&barr.work); | ||
| 2385 | return true; | 2365 | return true; | 
| 2386 | already_gone: | 2366 | already_gone: | 
| 2387 | spin_unlock_irq(&gcwq->lock); | 2367 | spin_unlock_irq(&gcwq->lock); | 
| 2388 | return false; | 2368 | return false; | 
| 2389 | } | 2369 | } | 
| 2370 | |||
| 2371 | /** | ||
| 2372 | * flush_work - wait for a work to finish executing the last queueing instance | ||
| 2373 | * @work: the work to flush | ||
| 2374 | * | ||
| 2375 | * Wait until @work has finished execution. This function considers | ||
| 2376 | * only the last queueing instance of @work. If @work has been | ||
| 2377 | * enqueued across different CPUs on a non-reentrant workqueue or on | ||
| 2378 | * multiple workqueues, @work might still be executing on return on | ||
| 2379 | * some of the CPUs from earlier queueing. | ||
| 2380 | * | ||
| 2381 | * If @work was queued only on a non-reentrant, ordered or unbound | ||
| 2382 | * workqueue, @work is guaranteed to be idle on return if it hasn't | ||
| 2383 | * been requeued since flush started. | ||
| 2384 | * | ||
| 2385 | * RETURNS: | ||
| 2386 | * %true if flush_work() waited for the work to finish execution, | ||
| 2387 | * %false if it was already idle. | ||
| 2388 | */ | ||
| 2389 | bool flush_work(struct work_struct *work) | ||
| 2390 | { | ||
| 2391 | struct wq_barrier barr; | ||
| 2392 | |||
| 2393 | if (start_flush_work(work, &barr, true)) { | ||
| 2394 | wait_for_completion(&barr.done); | ||
| 2395 | destroy_work_on_stack(&barr.work); | ||
| 2396 | return true; | ||
| 2397 | } else | ||
| 2398 | return false; | ||
| 2399 | } | ||
| 2390 | EXPORT_SYMBOL_GPL(flush_work); | 2400 | EXPORT_SYMBOL_GPL(flush_work); | 
| 2391 | 2401 | ||
| 2392 | static bool wait_on_cpu_work(struct global_cwq *gcwq, struct work_struct *work) | 2402 | static bool wait_on_cpu_work(struct global_cwq *gcwq, struct work_struct *work) | 
