task_work: Replace spin_unlock_wait() with lock/unlock pair
There is no agreed-upon definition of spin_unlock_wait()'s semantics, and it appears that all callers could do just as well with a lock/unlock pair. This commit therefore replaces the spin_unlock_wait() call in task_work_run() with a spin_lock_irq() and a spin_unlock_irq() aruond the cmpxchg() dequeue loop. This should be safe from a performance perspective because ->pi_lock is local to the task and because calls to the other side of the race, task_work_cancel(), should be rare. Signed-off-by: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
This commit is contained in:
parent
3ef0c7a730
commit
f274f1e72d
|
@ -96,20 +96,16 @@ void task_work_run(void)
|
||||||
* work->func() can do task_work_add(), do not set
|
* work->func() can do task_work_add(), do not set
|
||||||
* work_exited unless the list is empty.
|
* work_exited unless the list is empty.
|
||||||
*/
|
*/
|
||||||
|
raw_spin_lock_irq(&task->pi_lock);
|
||||||
do {
|
do {
|
||||||
work = READ_ONCE(task->task_works);
|
work = READ_ONCE(task->task_works);
|
||||||
head = !work && (task->flags & PF_EXITING) ?
|
head = !work && (task->flags & PF_EXITING) ?
|
||||||
&work_exited : NULL;
|
&work_exited : NULL;
|
||||||
} while (cmpxchg(&task->task_works, work, head) != work);
|
} while (cmpxchg(&task->task_works, work, head) != work);
|
||||||
|
raw_spin_unlock_irq(&task->pi_lock);
|
||||||
|
|
||||||
if (!work)
|
if (!work)
|
||||||
break;
|
break;
|
||||||
/*
|
|
||||||
* Synchronize with task_work_cancel(). It can't remove
|
|
||||||
* the first entry == work, cmpxchg(task_works) should
|
|
||||||
* fail, but it can play with *work and other entries.
|
|
||||||
*/
|
|
||||||
raw_spin_unlock_wait(&task->pi_lock);
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
next = work->next;
|
next = work->next;
|
||||||
|
|
Loading…
Reference in New Issue