2012-05-11 04:59:07 +04:00
# include <linux/spinlock.h>
# include <linux/task_work.h>
# include <linux/tracehook.h>
int
task_work_add ( struct task_struct * task , struct task_work * twork , bool notify )
{
unsigned long flags ;
int err = - ESRCH ;
# ifndef TIF_NOTIFY_RESUME
if ( notify )
return - ENOTSUPP ;
# endif
/*
* We must not insert the new work if the task has already passed
* exit_task_work ( ) . We rely on do_exit ( ) - > raw_spin_unlock_wait ( )
* and check PF_EXITING under pi_lock .
*/
raw_spin_lock_irqsave ( & task - > pi_lock , flags ) ;
if ( likely ( ! ( task - > flags & PF_EXITING ) ) ) {
2012-06-27 09:24:13 +04:00
struct task_work * last = task - > task_works ;
struct task_work * first = last ? last - > next : twork ;
twork - > next = first ;
if ( last )
last - > next = twork ;
task - > task_works = twork ;
2012-05-11 04:59:07 +04:00
err = 0 ;
}
raw_spin_unlock_irqrestore ( & task - > pi_lock , flags ) ;
/* test_and_set_bit() implies mb(), see tracehook_notify_resume(). */
if ( likely ( ! err ) & & notify )
set_notify_resume ( task ) ;
return err ;
}
struct task_work *
task_work_cancel ( struct task_struct * task , task_work_func_t func )
{
unsigned long flags ;
2012-06-27 09:24:13 +04:00
struct task_work * last , * res = NULL ;
2012-05-11 04:59:07 +04:00
raw_spin_lock_irqsave ( & task - > pi_lock , flags ) ;
2012-06-27 09:24:13 +04:00
last = task - > task_works ;
if ( last ) {
struct task_work * q = last , * p = q - > next ;
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 04:59:07 +04:00
}
}
raw_spin_unlock_irqrestore ( & task - > pi_lock , flags ) ;
2012-06-27 09:24:13 +04:00
return res ;
2012-05-11 04:59:07 +04:00
}
void task_work_run ( void )
{
struct task_struct * task = current ;
2012-06-27 09:24:13 +04:00
struct task_work * p , * q ;
2012-05-11 04:59:07 +04:00
raw_spin_lock_irq ( & task - > pi_lock ) ;
2012-06-27 09:24:13 +04:00
p = task - > task_works ;
task - > task_works = NULL ;
2012-05-11 04:59:07 +04:00
raw_spin_unlock_irq ( & task - > pi_lock ) ;
2012-06-27 09:24:13 +04:00
if ( unlikely ( ! p ) )
2012-05-11 04:59:07 +04:00
return ;
2012-06-27 09:24:13 +04:00
q = p - > next ; /* head */
p - > next = NULL ; /* cut it */
while ( q ) {
p = q - > next ;
q - > func ( q ) ;
q = p ;
2012-05-11 04:59:07 +04:00
}
}