/** * struct callback_head - callback structure for use with RCU and task_work * @next: next update requests in a list * @func: actual update function to call after the grace period. */ structcallback_head { structcallback_head *next; void (*func)(struct callback_head *head); };
staticstructcallback_headwork_exited;/* all we need is ->next == NULL */
/** * task_work_add - ask the @task to execute @work->func() * @task: the task which should run the callback * @work: the callback to run * @notify: send the notification if true * * Queue @work for task_work_run() below and notify the @task if @notify. * Fails if the @task is exiting/exited and thus it can't process this @work. * Otherwise @work->func() will be called when the @task returns from kernel * mode or exits. * * This is like the signal handler which runs in kernel mode, but it doesn't * try to wake up the @task. * * Note: there is no ordering guarantee on works queued here. * * RETURNS: * 0 if succeeds or -ESRCH. */ int task_work_add(struct task_struct *task, struct callback_head *work, bool notify) { structcallback_head *head;
do { head = READ_ONCE(task->task_works); if (unlikely(head == &work_exited)) return -ESRCH; work->next = head; } while (cmpxchg(&task->task_works, head, work) != head);
/** * tracehook_notify_resume - report when about to return to user mode * @regs: user-mode registers of @current task * * This is called when %TIF_NOTIFY_RESUME has been set. Now we are * about to return to user mode, and the user state in @regs can be * inspected or adjusted. The caller in arch code has cleared * %TIF_NOTIFY_RESUME before the call. If the flag gets set again * asynchronously, this will be called again before we return to * user mode. * * Called without locks. */ staticinlinevoidtracehook_notify_resume(struct pt_regs *regs) { /* * The caller just cleared TIF_NOTIFY_RESUME. This barrier * pairs with task_work_add()->set_notify_resume() after * hlist_add_head(task->task_works); */ smp_mb__after_atomic(); if (unlikely(current->task_works)) task_work_run();
/** * task_work_run - execute the works added by task_work_add() * * Flush the pending works. Should be used by the core kernel code. * Called before the task returns to the user-mode or stops, or when * it exits. In the latter case task_work_add() can no longer add the * new work after task_work_run() returns. */ voidtask_work_run(void) { structtask_struct *task = current; structcallback_head *work, *head, *next;
for (;;) { /* * 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;
do { next = work->next; work->func(work); work = next; cond_resched(); } while (work); } }