1e73f8959SOleg Nesterov #include <linux/spinlock.h> 2e73f8959SOleg Nesterov #include <linux/task_work.h> 3e73f8959SOleg Nesterov #include <linux/tracehook.h> 4e73f8959SOleg Nesterov 5e73f8959SOleg Nesterov int 667d12145SAl Viro task_work_add(struct task_struct *task, struct callback_head *twork, bool notify) 7e73f8959SOleg Nesterov { 8ed3e694dSAl Viro struct callback_head *last, *first; 9e73f8959SOleg Nesterov unsigned long flags; 10e73f8959SOleg Nesterov 11e73f8959SOleg Nesterov /* 12ed3e694dSAl Viro * Not inserting the new work if the task has already passed 13ed3e694dSAl Viro * exit_task_work() is the responisbility of callers. 14e73f8959SOleg Nesterov */ 15e73f8959SOleg Nesterov raw_spin_lock_irqsave(&task->pi_lock, flags); 16ed3e694dSAl Viro last = task->task_works; 17ed3e694dSAl Viro first = last ? last->next : twork; 18158e1645SAl Viro twork->next = first; 19158e1645SAl Viro if (last) 20158e1645SAl Viro last->next = twork; 21158e1645SAl Viro task->task_works = twork; 22e73f8959SOleg Nesterov raw_spin_unlock_irqrestore(&task->pi_lock, flags); 23e73f8959SOleg Nesterov 24e73f8959SOleg Nesterov /* test_and_set_bit() implies mb(), see tracehook_notify_resume(). */ 25ed3e694dSAl Viro if (notify) 26e73f8959SOleg Nesterov set_notify_resume(task); 27ed3e694dSAl Viro return 0; 28e73f8959SOleg Nesterov } 29e73f8959SOleg Nesterov 3067d12145SAl Viro struct callback_head * 31e73f8959SOleg Nesterov task_work_cancel(struct task_struct *task, task_work_func_t func) 32e73f8959SOleg Nesterov { 33e73f8959SOleg Nesterov unsigned long flags; 3467d12145SAl Viro struct callback_head *last, *res = NULL; 35e73f8959SOleg Nesterov 36e73f8959SOleg Nesterov raw_spin_lock_irqsave(&task->pi_lock, flags); 37158e1645SAl Viro last = task->task_works; 38158e1645SAl Viro if (last) { 3967d12145SAl Viro struct callback_head *q = last, *p = q->next; 40158e1645SAl Viro while (1) { 41158e1645SAl Viro if (p->func == func) { 42158e1645SAl Viro q->next = p->next; 43158e1645SAl Viro if (p == last) 44158e1645SAl Viro task->task_works = q == p ? NULL : q; 45158e1645SAl Viro res = p; 46158e1645SAl Viro break; 47158e1645SAl Viro } 48158e1645SAl Viro if (p == last) 49158e1645SAl Viro break; 50158e1645SAl Viro q = p; 51158e1645SAl Viro p = q->next; 52e73f8959SOleg Nesterov } 53e73f8959SOleg Nesterov } 54e73f8959SOleg Nesterov raw_spin_unlock_irqrestore(&task->pi_lock, flags); 55158e1645SAl Viro return res; 56e73f8959SOleg Nesterov } 57e73f8959SOleg Nesterov 58e73f8959SOleg Nesterov void task_work_run(void) 59e73f8959SOleg Nesterov { 60e73f8959SOleg Nesterov struct task_struct *task = current; 6167d12145SAl Viro struct callback_head *p, *q; 62e73f8959SOleg Nesterov 63a2d4c71dSAl Viro while (1) { 64e73f8959SOleg Nesterov raw_spin_lock_irq(&task->pi_lock); 65158e1645SAl Viro p = task->task_works; 66158e1645SAl Viro task->task_works = NULL; 67e73f8959SOleg Nesterov raw_spin_unlock_irq(&task->pi_lock); 68e73f8959SOleg Nesterov 69158e1645SAl Viro if (unlikely(!p)) 70e73f8959SOleg Nesterov return; 71e73f8959SOleg Nesterov 72158e1645SAl Viro q = p->next; /* head */ 73158e1645SAl Viro p->next = NULL; /* cut it */ 74158e1645SAl Viro while (q) { 75158e1645SAl Viro p = q->next; 76158e1645SAl Viro q->func(q); 77158e1645SAl Viro q = p; 78e73f8959SOleg Nesterov } 79e73f8959SOleg Nesterov } 80a2d4c71dSAl Viro } 81