2012-05-11 10:59:07 +10:00
# include <linux/spinlock.h>
# include <linux/task_work.h>
# include <linux/tracehook.h>
int
2012-06-27 11:07:19 +04:00
task_work_add ( struct task_struct * task , struct callback_head * twork , bool notify )
2012-05-11 10:59:07 +10:00
{
2012-06-27 11:31:24 +04:00
struct callback_head * last , * first ;
2012-05-11 10:59:07 +10:00
unsigned long flags ;
/*
2012-06-27 11:31:24 +04:00
* Not inserting the new work if the task has already passed
* exit_task_work ( ) is the responisbility of callers .
2012-05-11 10:59:07 +10:00
*/
raw_spin_lock_irqsave ( & task - > pi_lock , flags ) ;
2012-06-27 11:31:24 +04:00
last = task - > task_works ;
first = last ? last - > next : twork ;
twork - > next = first ;
if ( last )
last - > next = twork ;
task - > task_works = twork ;
2012-05-11 10:59:07 +10:00
raw_spin_unlock_irqrestore ( & task - > pi_lock , flags ) ;
/* test_and_set_bit() implies mb(), see tracehook_notify_resume(). */
2012-06-27 11:31:24 +04:00
if ( notify )
2012-05-11 10:59:07 +10:00
set_notify_resume ( task ) ;
2012-06-27 11:31:24 +04:00
return 0 ;
2012-05-11 10:59:07 +10:00
}
2012-06-27 11:07:19 +04:00
struct callback_head *
2012-05-11 10:59:07 +10:00
task_work_cancel ( struct task_struct * task , task_work_func_t func )
{
unsigned long flags ;
2012-06-27 11:07:19 +04:00
struct callback_head * last , * res = NULL ;
2012-05-11 10:59:07 +10:00
raw_spin_lock_irqsave ( & task - > pi_lock , flags ) ;
2012-06-27 09:24:13 +04:00
last = task - > task_works ;
if ( last ) {
2012-06-27 11:07:19 +04:00
struct callback_head * q = last , * p = q - > next ;
2012-06-27 09:24:13 +04:00
while ( 1 ) {
if ( p - > func = = func ) {
q - > next = p - > next ;
if ( p = = last )
task - > task_works = q = = p ? NULL : q ;
res = p ;
break ;
}
if ( p = = last )
break ;
q = p ;
p = q - > next ;
2012-05-11 10:59:07 +10:00
}
}
raw_spin_unlock_irqrestore ( & task - > pi_lock , flags ) ;
2012-06-27 09:24:13 +04:00
return res ;
2012-05-11 10:59:07 +10:00
}
void task_work_run ( void )
{
struct task_struct * task = current ;
2012-06-27 11:07:19 +04:00
struct callback_head * p , * q ;
2012-05-11 10:59:07 +10:00
2012-06-27 11:33:29 +04:00
while ( 1 ) {
raw_spin_lock_irq ( & task - > pi_lock ) ;
p = task - > task_works ;
task - > task_works = NULL ;
raw_spin_unlock_irq ( & task - > pi_lock ) ;
2012-05-11 10:59:07 +10:00
2012-06-27 11:33:29 +04:00
if ( unlikely ( ! p ) )
return ;
2012-05-11 10:59:07 +10:00
2012-06-27 11:33:29 +04:00
q = p - > next ; /* head */
p - > next = NULL ; /* cut it */
while ( q ) {
p = q - > next ;
q - > func ( q ) ;
q = p ;
2012-08-21 15:05:14 +02:00
cond_resched ( ) ;
2012-06-27 11:33:29 +04:00
}
2012-05-11 10:59:07 +10:00
}
}