Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 323602
b: refs/heads/master
c: 9da33de
h: refs/heads/master
v: v3
  • Loading branch information
Oleg Nesterov authored and Ingo Molnar committed Sep 13, 2012
1 parent cae29d8 commit 099402f
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 9 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: ac3d0da8f3290b3d394cdb7f50604424a7cd6092
refs/heads/master: 9da33de62431c7839f98156720862262272a8380
3 changes: 1 addition & 2 deletions trunk/include/linux/task_work.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ void task_work_run(void);

static inline void exit_task_work(struct task_struct *task)
{
if (unlikely(task->task_works))
task_work_run();
task_work_run();
}

#endif /* _LINUX_TASK_WORK_H */
22 changes: 16 additions & 6 deletions trunk/kernel/task_work.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@
#include <linux/task_work.h>
#include <linux/tracehook.h>

static struct callback_head work_exited; /* all we need is ->next == NULL */

int
task_work_add(struct task_struct *task, struct callback_head *work, bool notify)
{
struct callback_head *head;
/*
* Not inserting the new work if the task has already passed
* exit_task_work() is the responisbility of callers.
*/

do {
head = ACCESS_ONCE(task->task_works);
if (unlikely(head == &work_exited))
return -ESRCH;
work->next = head;
} while (cmpxchg(&task->task_works, head, work) != head);

Expand All @@ -30,7 +31,7 @@ task_work_cancel(struct task_struct *task, task_work_func_t func)
* If cmpxchg() fails we continue without updating pprev.
* Either we raced with task_work_add() which added the
* new entry before this work, we will find it again. Or
* we raced with task_work_run(), *pprev == NULL.
* we raced with task_work_run(), *pprev == NULL/exited.
*/
raw_spin_lock_irqsave(&task->pi_lock, flags);
while ((work = ACCESS_ONCE(*pprev))) {
Expand All @@ -51,7 +52,16 @@ void task_work_run(void)
struct callback_head *work, *head, *next;

for (;;) {
work = xchg(&task->task_works, NULL);
/*
* work->func() can do task_work_add(), do not set
* work_exited unless the list is empty.
*/
do {
work = ACCESS_ONCE(task->task_works);
head = !work && (task->flags & PF_EXITING) ?
&work_exited : NULL;
} while (cmpxchg(&task->task_works, work, head) != work);

if (!work)
break;
/*
Expand Down

0 comments on commit 099402f

Please sign in to comment.