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
1 changed files with 2 additions and 6 deletions
|
@ -96,20 +96,16 @@ void task_work_run(void)
|
|||
* work->func() can do task_work_add(), do not set
|
||||
* work_exited unless the list is empty.
|
||||
*/
|
||||
raw_spin_lock_irq(&task->pi_lock);
|
||||
do {
|
||||
work = READ_ONCE(task->task_works);
|
||||
head = !work && (task->flags & PF_EXITING) ?
|
||||
&work_exited : NULL;
|
||||
} while (cmpxchg(&task->task_works, work, head) != work);
|
||||
raw_spin_unlock_irq(&task->pi_lock);
|
||||
|
||||
if (!work)
|
||||
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 {
|
||||
next = work->next;
|
||||
|
|
Loading…
Reference in a new issue