2005-04-17 02:20:36 +04:00
/*
* drivers / power / process . c - Functions for starting / stopping processes on
* suspend transitions .
*
* Originally from swsusp .
*/
# undef DEBUG
# include <linux/interrupt.h>
2009-09-22 04:03:09 +04:00
# include <linux/oom.h>
2005-04-17 02:20:36 +04:00
# include <linux/suspend.h>
# include <linux/module.h>
2006-03-23 14:00:04 +03:00
# include <linux/syscalls.h>
2006-12-07 07:34:23 +03:00
# include <linux/freezer.h>
2009-10-09 00:47:30 +04:00
# include <linux/delay.h>
2010-06-29 12:07:12 +04:00
# include <linux/workqueue.h>
2005-04-17 02:20:36 +04:00
/*
* Timeout for stopping processes
*/
2006-03-23 14:00:04 +03:00
# define TIMEOUT (20 * HZ)
2005-04-17 02:20:36 +04:00
2011-11-22 00:32:26 +04:00
static int try_to_freeze_tasks ( bool user_only )
2005-04-17 02:20:36 +04:00
{
struct task_struct * g , * p ;
2006-12-07 07:34:40 +03:00
unsigned long end_time ;
unsigned int todo ;
2010-06-29 12:07:12 +04:00
bool wq_busy = false ;
2007-10-18 14:04:49 +04:00
struct timeval start , end ;
2008-07-24 08:28:44 +04:00
u64 elapsed_csecs64 ;
2007-10-18 14:04:49 +04:00
unsigned int elapsed_csecs ;
2010-10-05 00:07:32 +04:00
bool wakeup = false ;
2007-10-18 14:04:49 +04:00
do_gettimeofday ( & start ) ;
2005-06-25 10:13:50 +04:00
2006-12-07 07:34:40 +03:00
end_time = jiffies + TIMEOUT ;
2010-06-29 12:07:12 +04:00
2011-11-22 00:32:26 +04:00
if ( ! user_only )
2010-06-29 12:07:12 +04:00
freeze_workqueues_begin ( ) ;
2009-10-09 00:47:30 +04:00
while ( true ) {
2006-12-07 07:34:40 +03:00
todo = 0 ;
2005-04-17 02:20:36 +04:00
read_lock ( & tasklist_lock ) ;
do_each_thread ( g , p ) {
2011-11-22 00:32:26 +04:00
if ( p = = current | | ! freeze_task ( p ) )
2007-10-18 14:04:46 +04:00
continue ;
2008-03-04 07:22:05 +03:00
/*
* Now that we ' ve done set_freeze_flag , don ' t
* perturb a task in TASK_STOPPED or TASK_TRACED .
* It is " frozen enough " . If the task does wake
* up , it will immediately call try_to_freeze .
2010-11-27 01:07:27 +03:00
*
* Because freeze_task ( ) goes through p ' s
* scheduler lock after setting TIF_FREEZE , it ' s
* guaranteed that either we see TASK_RUNNING or
* try_to_stop ( ) after schedule ( ) in ptrace / signal
* stop sees TIF_FREEZE .
2008-03-04 07:22:05 +03:00
*/
if ( ! task_is_stopped_or_traced ( p ) & &
! freezer_should_skip ( p ) )
2007-05-24 00:57:25 +04:00
todo + + ;
2005-04-17 02:20:36 +04:00
} while_each_thread ( g , p ) ;
read_unlock ( & tasklist_lock ) ;
2010-06-29 12:07:12 +04:00
2011-11-22 00:32:26 +04:00
if ( ! user_only ) {
2010-06-29 12:07:12 +04:00
wq_busy = freeze_workqueues_busy ( ) ;
todo + = wq_busy ;
}
2009-10-09 00:47:30 +04:00
if ( ! todo | | time_after ( jiffies , end_time ) )
2005-09-04 02:57:05 +04:00
break ;
2009-10-09 00:47:30 +04:00
2010-12-04 00:58:31 +03:00
if ( pm_wakeup_pending ( ) ) {
2010-10-05 00:07:32 +04:00
wakeup = true ;
break ;
}
2009-10-09 00:47:30 +04:00
/*
* We need to retry , but first give the freezing tasks some
* time to enter the regrigerator .
*/
msleep ( 10 ) ;
}
2005-06-25 10:13:50 +04:00
2007-10-18 14:04:49 +04:00
do_gettimeofday ( & end ) ;
elapsed_csecs64 = timeval_to_ns ( & end ) - timeval_to_ns ( & start ) ;
do_div ( elapsed_csecs64 , NSEC_PER_SEC / 100 ) ;
elapsed_csecs = elapsed_csecs64 ;
2005-09-04 02:57:05 +04:00
if ( todo ) {
2006-12-07 07:34:26 +03:00
printk ( " \n " ) ;
2010-10-05 00:07:32 +04:00
printk ( KERN_ERR " Freezing of tasks %s after %d.%02d seconds "
2010-06-29 12:07:12 +04:00
" (%d tasks refusing to freeze, wq_busy=%d): \n " ,
2010-10-05 00:07:32 +04:00
wakeup ? " aborted " : " failed " ,
2010-06-29 12:07:12 +04:00
elapsed_csecs / 100 , elapsed_csecs % 100 ,
todo - wq_busy , wq_busy ) ;
2005-09-04 02:57:05 +04:00
read_lock ( & tasklist_lock ) ;
2006-03-23 14:00:04 +03:00
do_each_thread ( g , p ) {
2011-11-22 00:32:24 +04:00
if ( ! wakeup & & ! freezer_should_skip ( p ) & &
2011-11-22 00:32:25 +04:00
p ! = current & & freezing ( p ) & & ! frozen ( p ) )
2010-03-11 00:59:13 +03:00
sched_show_task ( p ) ;
2006-03-23 14:00:04 +03:00
} while_each_thread ( g , p ) ;
2005-09-04 02:57:05 +04:00
read_unlock ( & tasklist_lock ) ;
2007-10-18 14:04:49 +04:00
} else {
printk ( " (elapsed %d.%02d seconds) " , elapsed_csecs / 100 ,
elapsed_csecs % 100 ) ;
2005-09-04 02:57:05 +04:00
}
2007-07-19 12:47:34 +04:00
return todo ? - EBUSY : 0 ;
2006-12-07 07:34:40 +03:00
}
/**
2011-09-26 22:32:27 +04:00
* freeze_processes - Signal user space processes to enter the refrigerator .
2011-11-22 00:32:24 +04:00
*
* On success , returns 0. On failure , - errno and system is fully thawed .
2006-12-07 07:34:40 +03:00
*/
int freeze_processes ( void )
{
2007-07-19 12:47:34 +04:00
int error ;
2006-12-07 07:34:40 +03:00
2011-11-22 00:32:25 +04:00
if ( ! pm_freezing )
atomic_inc ( & system_freezing_cnt ) ;
2007-10-18 14:04:48 +04:00
printk ( " Freezing user space processes ... " ) ;
2011-11-22 00:32:25 +04:00
pm_freezing = true ;
2008-06-12 00:04:29 +04:00
error = try_to_freeze_tasks ( true ) ;
2011-09-26 22:32:27 +04:00
if ( ! error ) {
printk ( " done. " ) ;
oom_killer_disable ( ) ;
}
printk ( " \n " ) ;
BUG_ON ( in_atomic ( ) ) ;
2011-11-22 00:32:24 +04:00
if ( error )
thaw_processes ( ) ;
2011-09-26 22:32:27 +04:00
return error ;
}
/**
* freeze_kernel_threads - Make freezable kernel threads go to the refrigerator .
2011-11-22 00:32:24 +04:00
*
* On success , returns 0. On failure , - errno and system is fully thawed .
2011-09-26 22:32:27 +04:00
*/
int freeze_kernel_threads ( void )
{
int error ;
2006-12-07 07:34:40 +03:00
2007-10-18 14:04:48 +04:00
printk ( " Freezing remaining freezable tasks ... " ) ;
2011-11-22 00:32:25 +04:00
pm_nosig_freezing = true ;
2008-06-12 00:04:29 +04:00
error = try_to_freeze_tasks ( false ) ;
2011-09-26 22:32:27 +04:00
if ( ! error )
printk ( " done. " ) ;
2009-06-17 02:32:41 +04:00
2007-10-18 14:04:48 +04:00
printk ( " \n " ) ;
2011-09-26 22:32:27 +04:00
BUG_ON ( in_atomic ( ) ) ;
2009-06-17 02:32:41 +04:00
2011-11-22 00:32:24 +04:00
if ( error )
thaw_processes ( ) ;
2007-10-18 14:04:48 +04:00
return error ;
2005-04-17 02:20:36 +04:00
}
2011-11-22 00:32:23 +04:00
void thaw_processes ( void )
2005-04-17 02:20:36 +04:00
{
struct task_struct * g , * p ;
2011-11-22 00:32:25 +04:00
if ( pm_freezing )
atomic_dec ( & system_freezing_cnt ) ;
pm_freezing = false ;
pm_nosig_freezing = false ;
2011-11-22 00:32:23 +04:00
oom_killer_enable ( ) ;
printk ( " Restarting tasks ... " ) ;
thaw_workqueues ( ) ;
2005-04-17 02:20:36 +04:00
read_lock ( & tasklist_lock ) ;
2006-12-07 07:34:37 +03:00
do_each_thread ( g , p ) {
2011-11-22 00:32:23 +04:00
__thaw_task ( p ) ;
2006-12-07 07:34:37 +03:00
} while_each_thread ( g , p ) ;
2005-04-17 02:20:36 +04:00
read_unlock ( & tasklist_lock ) ;
2009-06-17 02:32:41 +04:00
2005-04-17 02:20:36 +04:00
schedule ( ) ;
2006-12-07 07:34:26 +03:00
printk ( " done. \n " ) ;
2005-04-17 02:20:36 +04:00
}
2012-01-29 23:35:52 +04:00
void thaw_kernel_threads ( void )
{
struct task_struct * g , * p ;
pm_nosig_freezing = false ;
printk ( " Restarting kernel threads ... " ) ;
thaw_workqueues ( ) ;
read_lock ( & tasklist_lock ) ;
do_each_thread ( g , p ) {
if ( p - > flags & ( PF_KTHREAD | PF_WQ_WORKER ) )
__thaw_task ( p ) ;
} while_each_thread ( g , p ) ;
read_unlock ( & tasklist_lock ) ;
schedule ( ) ;
printk ( " done. \n " ) ;
}