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>
# 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>
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
static inline int freezeable ( struct task_struct * p )
{
2007-05-08 11:24:01 +04:00
if ( ( p = = current ) | |
2005-04-17 02:20:36 +04:00
( p - > flags & PF_NOFREEZE ) | |
2007-05-08 11:24:01 +04:00
( p - > exit_state ! = 0 ) )
2005-04-17 02:20:36 +04:00
return 0 ;
return 1 ;
}
2008-06-12 00:04:29 +04:00
static int try_to_freeze_tasks ( bool sig_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 ;
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 ;
do_gettimeofday ( & start ) ;
2005-06-25 10:13:50 +04:00
2006-12-07 07:34:40 +03:00
end_time = jiffies + TIMEOUT ;
2005-04-17 02:20:36 +04:00
do {
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 ) {
2007-07-19 12:47:33 +04:00
if ( frozen ( p ) | | ! freezeable ( p ) )
2005-04-17 02:20:36 +04:00
continue ;
2006-12-07 07:34:40 +03:00
2008-06-12 00:04:29 +04:00
if ( ! freeze_task ( p , sig_only ) )
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 .
*/
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 ) ;
yield ( ) ; /* Yield is okay here */
2007-07-19 12:47:35 +04:00
if ( time_after ( jiffies , end_time ) )
2005-09-04 02:57:05 +04:00
break ;
2006-12-07 07:34:40 +03:00
} while ( todo ) ;
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:40 +03:00
/* This does not unfreeze processes that are already frozen
* ( we have slightly ugly calling convention in that respect ,
* and caller must call thaw_processes ( ) if something fails ) ,
* but it cleans up leftover PF_FREEZE requests .
*/
2006-12-07 07:34:26 +03:00
printk ( " \n " ) ;
2007-10-18 14:04:49 +04:00
printk ( KERN_ERR " Freezing of tasks failed after %d.%02d seconds "
2006-12-07 07:34:40 +03:00
" (%d tasks refusing to freeze): \n " ,
2007-10-18 14:04:49 +04:00
elapsed_csecs / 100 , elapsed_csecs % 100 , todo ) ;
2007-07-19 12:47:26 +04:00
show_state ( ) ;
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 ) {
2007-05-24 00:57:24 +04:00
task_lock ( p ) ;
2007-07-19 12:47:33 +04:00
if ( freezing ( p ) & & ! freezer_should_skip ( p ) )
2006-12-07 07:34:26 +03:00
printk ( KERN_ERR " %s \n " , p - > comm ) ;
2006-08-05 23:13:42 +04:00
cancel_freezing ( p ) ;
2007-05-24 00:57:24 +04:00
task_unlock ( 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
}
/**
* freeze_processes - tell processes to enter the refrigerator
*/
int freeze_processes ( void )
{
2007-07-19 12:47:34 +04:00
int error ;
2006-12-07 07:34:40 +03:00
2007-10-18 14:04:48 +04:00
printk ( " Freezing user space processes ... " ) ;
2008-06-12 00:04:29 +04:00
error = try_to_freeze_tasks ( true ) ;
2007-07-19 12:47:34 +04:00
if ( error )
2007-10-18 14:04:48 +04:00
goto Exit ;
printk ( " done. \n " ) ;
2006-12-07 07:34:40 +03:00
2007-10-18 14:04:48 +04:00
printk ( " Freezing remaining freezable tasks ... " ) ;
2008-06-12 00:04:29 +04:00
error = try_to_freeze_tasks ( false ) ;
2007-07-19 12:47:34 +04:00
if ( error )
2007-10-18 14:04:48 +04:00
goto Exit ;
printk ( " done. " ) ;
Exit :
2005-04-17 02:20:36 +04:00
BUG_ON ( in_atomic ( ) ) ;
2007-10-18 14:04:48 +04:00
printk ( " \n " ) ;
return error ;
2005-04-17 02:20:36 +04:00
}
2008-06-12 00:04:29 +04:00
static void thaw_tasks ( bool nosig_only )
2005-04-17 02:20:36 +04:00
{
struct task_struct * g , * p ;
read_lock ( & tasklist_lock ) ;
2006-12-07 07:34:37 +03:00
do_each_thread ( g , p ) {
if ( ! freezeable ( p ) )
continue ;
2006-12-07 07:34:28 +03:00
2008-06-12 00:04:29 +04:00
if ( nosig_only & & should_send_signal ( p ) )
2006-12-07 07:34:37 +03:00
continue ;
2005-04-17 02:20:36 +04:00
2008-10-19 07:27:22 +04:00
if ( cgroup_frozen ( p ) )
continue ;
2007-05-24 00:57:25 +04:00
thaw_process ( 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 ) ;
2006-12-07 07:34:37 +03:00
}
void thaw_processes ( void )
{
printk ( " Restarting tasks ... " ) ;
2008-06-12 00:04:29 +04:00
thaw_tasks ( true ) ;
thaw_tasks ( false ) ;
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
}