diff options
author | Tejun Heo <tj@kernel.org> | 2012-08-03 10:30:45 -0700 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2012-08-03 10:30:45 -0700 |
commit | 8930caba3dbdd8b86dd6934a5920bf61b53a931e (patch) | |
tree | 1ef91c823238ffe3e26af1d1d48678f299185058 /include | |
parent | 959d1af8cffc8fd38ed53e8be1cf4ab8782f9c00 (diff) | |
download | op-kernel-dev-8930caba3dbdd8b86dd6934a5920bf61b53a931e.zip op-kernel-dev-8930caba3dbdd8b86dd6934a5920bf61b53a931e.tar.gz |
workqueue: disable irq while manipulating PENDING
Queueing operations use WORK_STRUCT_PENDING_BIT to synchronize access
to the target work item. They first try to claim the bit and proceed
with queueing only after that succeeds and there's a window between
PENDING being set and the actual queueing where the task can be
interrupted or preempted.
There's also a similar window in process_one_work() when clearing
PENDING. A work item is dequeued, gcwq->lock is released and then
PENDING is cleared and the worker might get interrupted or preempted
between releasing gcwq->lock and clearing PENDING.
cancel[_delayed]_work_sync() tries to claim or steal PENDING. The
function assumes that a work item with PENDING is either queued or in
the process of being [de]queued. In the latter case, it busy-loops
until either the work item loses PENDING or is queued. If canceling
coincides with the above described interrupts or preemptions, the
canceling task will busy-loop while the queueing or executing task is
preempted.
This patch keeps irq disabled across claiming PENDING and actual
queueing and moves PENDING clearing in process_one_work() inside
gcwq->lock so that busy looping from PENDING && !queued doesn't wait
for interrupted/preempted tasks. Note that, in process_one_work(),
setting last CPU and clearing PENDING got merged into single
operation.
This removes possible long busy-loops and will allow using
try_to_grab_pending() from bh and irq contexts.
v2: __queue_work() was testing preempt_count() to ensure that the
caller has disabled preemption. This triggers spuriously if
!CONFIG_PREEMPT_COUNT. Use preemptible() instead. Reported by
Fengguang Wu.
v3: Disable irq instead of preemption. IRQ will be disabled while
grabbing gcwq->lock later anyway and this allows using
try_to_grab_pending() from bh and irq contexts.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Fengguang Wu <fengguang.wu@intel.com>
Diffstat (limited to 'include')
0 files changed, 0 insertions, 0 deletions