workqueue: make work_busy() test WORK_STRUCT_PENDING first
authorLai Jiangshan <laijs@cn.fujitsu.com>
Thu, 7 Feb 2013 02:04:53 +0000 (18:04 -0800)
committerTejun Heo <tj@kernel.org>
Thu, 7 Feb 2013 02:04:53 +0000 (18:04 -0800)
Currently, work_busy() first tests whether the work has a pool
associated with it and if not, considers it idle.  This works fine
even for delayed_work.work queued on timer, as __queue_delayed_work()
sets cwq on delayed_work.work - a queued delayed_work always has its
cwq and thus pool associated with it.

However, we're about to update delayed_work queueing and this won't
hold.  Update work_busy() such that it tests WORK_STRUCT_PENDING
before the associated pool.  This doesn't make any noticeable behavior
difference now.

With work_pending() test moved, the function read a lot better with
"if (!pool)" test flipped to positive.  Flip it.

While at it, lose the comment about now non-existent reentrant
workqueues.

tj: Reorganized the function and rewrote the description.

Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
kernel/workqueue.c

index 7e11334a119fb43907ea1cea1359be2d6719fe65..a229a56f3a32cc6879a3a34e2108049e4fc5c5bd 100644 (file)
@@ -3443,8 +3443,6 @@ EXPORT_SYMBOL_GPL(workqueue_congested);
  * Test whether @work is currently pending or running.  There is no
  * synchronization around this function and the test result is
  * unreliable and only useful as advisory hints or for debugging.
- * Especially for reentrant wqs, the pending state might hide the
- * running state.
  *
  * RETURNS:
  * OR'd bitmask of WORK_BUSY_* bits.
@@ -3455,17 +3453,15 @@ unsigned int work_busy(struct work_struct *work)
        unsigned long flags;
        unsigned int ret = 0;
 
-       if (!pool)
-               return 0;
-
-       spin_lock_irqsave(&pool->lock, flags);
-
        if (work_pending(work))
                ret |= WORK_BUSY_PENDING;
-       if (find_worker_executing_work(pool, work))
-               ret |= WORK_BUSY_RUNNING;
 
-       spin_unlock_irqrestore(&pool->lock, flags);
+       if (pool) {
+               spin_lock_irqsave(&pool->lock, flags);
+               if (find_worker_executing_work(pool, work))
+                       ret |= WORK_BUSY_RUNNING;
+               spin_unlock_irqrestore(&pool->lock, flags);
+       }
 
        return ret;
 }