summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2010-03-15 14:53:31 +1100
committerStephen Rothwell <sfr@canb.auug.org.au>2010-03-15 14:53:31 +1100
commit98d18c7d511450cbaa9ee95cc8c3f22b6d1fe8b2 (patch)
tree5ccc33789f7453398adb8994a50f308edf297934
parent506d00c3279189b46e3df8d384f2fd3cf3ed730d (diff)
parent5ab0fec5e715dd22e9d30d9f2eb1f0bbb05fb001 (diff)
Merge remote branch 'workqueues/for-next'
-rw-r--r--kernel/workqueue.c27
1 files changed, 26 insertions, 1 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index dee48658805c..b156dd6c87f3 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -482,7 +482,8 @@ static int flush_cpu_workqueue(struct cpu_workqueue_struct *cwq)
int active = 0;
struct wq_barrier barr;
- WARN_ON(cwq->thread == current);
+ if (WARN_ON(cwq->thread == current))
+ return 1;
spin_lock_irq(&cwq->lock);
if (!list_empty(&cwq->worklist) || cwq->current_work != NULL) {
@@ -845,6 +846,30 @@ int schedule_on_each_cpu(work_func_t func)
return 0;
}
+/**
+ * flush_scheduled_work - ensure that any scheduled work has run to completion.
+ *
+ * Forces execution of the kernel-global workqueue and blocks until its
+ * completion.
+ *
+ * Think twice before calling this function! It's very easy to get into
+ * trouble if you don't take great care. Either of the following situations
+ * will lead to deadlock:
+ *
+ * One of the work items currently on the workqueue needs to acquire
+ * a lock held by your code or its caller.
+ *
+ * Your code is running in the context of a work routine.
+ *
+ * They will be detected by lockdep when they occur, but the first might not
+ * occur very often. It depends on what work items are on the workqueue and
+ * what locks they need, which you have no control over.
+ *
+ * In most situations flushing the entire workqueue is overkill; you merely
+ * need to know that a particular work item isn't queued and isn't running.
+ * In such cases you should use cancel_delayed_work_sync() or
+ * cancel_work_sync() instead.
+ */
void flush_scheduled_work(void)
{
flush_workqueue(keventd_wq);