2019-05-19 15:08:55 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2008-10-19 07:27:19 +04:00
/*
* kernel / freezer . c - Function to freeze a process
*
* Originally from kernel / power / process . c
*/
# include <linux/interrupt.h>
# include <linux/suspend.h>
2011-05-23 22:51:41 +04:00
# include <linux/export.h>
2008-10-19 07:27:19 +04:00
# include <linux/syscalls.h>
# include <linux/freezer.h>
2011-11-22 00:32:23 +04:00
# include <linux/kthread.h>
2008-10-19 07:27:19 +04:00
2011-11-22 00:32:25 +04:00
/* total number of freezing conditions in effect */
atomic_t system_freezing_cnt = ATOMIC_INIT ( 0 ) ;
EXPORT_SYMBOL ( system_freezing_cnt ) ;
2018-07-31 11:51:32 +03:00
/* indicate whether PM freezing is in effect, protected by
* system_transition_mutex
*/
2011-11-22 00:32:25 +04:00
bool pm_freezing ;
bool pm_nosig_freezing ;
2011-11-22 00:32:24 +04:00
/* protects freezing and frozen transitions */
static DEFINE_SPINLOCK ( freezer_lock ) ;
2008-10-19 07:27:19 +04:00
2011-11-22 00:32:25 +04:00
/**
* freezing_slow_path - slow path for testing whether a task needs to be frozen
* @ p : task to be tested
*
* This function is called by freezing ( ) if system_freezing_cnt isn ' t zero
* and tests whether @ p needs to enter and stay in frozen state . Can be
* called under any context . The freezers are responsible for ensuring the
* target tasks see the updated state .
*/
bool freezing_slow_path ( struct task_struct * p )
{
2013-07-25 04:41:33 +04:00
if ( p - > flags & ( PF_NOFREEZE | PF_SUSPEND_TASK ) )
2011-11-22 00:32:25 +04:00
return false ;
2016-07-29 01:45:16 +03:00
if ( test_tsk_thread_flag ( p , TIF_MEMDIE ) )
2014-10-21 11:27:12 +04:00
return false ;
2011-11-22 00:32:25 +04:00
if ( pm_nosig_freezing | | cgroup_freezing ( p ) )
return true ;
2011-11-23 21:28:17 +04:00
if ( pm_freezing & & ! ( p - > flags & PF_KTHREAD ) )
2011-11-22 00:32:25 +04:00
return true ;
return false ;
}
EXPORT_SYMBOL ( freezing_slow_path ) ;
2008-10-19 07:27:19 +04:00
/* Refrigerator is place where frozen processes are stored :-). */
2011-11-22 00:32:23 +04:00
bool __refrigerator ( bool check_kthr_stop )
2008-10-19 07:27:19 +04:00
{
/* Hmm, should we be allowed to suspend when there are realtime
processes around ? */
2011-11-22 00:32:22 +04:00
bool was_frozen = false ;
2011-11-22 00:32:26 +04:00
long save = current - > state ;
2008-10-19 07:27:19 +04:00
pr_debug ( " %s entered refrigerator \n " , current - > comm ) ;
for ( ; ; ) {
set_current_state ( TASK_UNINTERRUPTIBLE ) ;
2011-11-22 00:32:26 +04:00
spin_lock_irq ( & freezer_lock ) ;
current - > flags | = PF_FROZEN ;
2011-11-22 00:32:24 +04:00
if ( ! freezing ( current ) | |
2011-11-22 00:32:23 +04:00
( check_kthr_stop & & kthread_should_stop ( ) ) )
2011-11-22 00:32:26 +04:00
current - > flags & = ~ PF_FROZEN ;
spin_unlock_irq ( & freezer_lock ) ;
if ( ! ( current - > flags & PF_FROZEN ) )
2008-10-19 07:27:19 +04:00
break ;
2011-11-22 00:32:22 +04:00
was_frozen = true ;
2008-10-19 07:27:19 +04:00
schedule ( ) ;
}
2009-07-17 16:15:47 +04:00
2008-10-19 07:27:19 +04:00
pr_debug ( " %s left refrigerator \n " , current - > comm ) ;
2011-11-22 00:32:22 +04:00
/*
* Restore saved task state before returning . The mb ' d version
* needs to be used ; otherwise , it might silently break
* synchronization which depends on ordered task state change .
*/
set_current_state ( save ) ;
2011-11-22 00:32:22 +04:00
return was_frozen ;
2008-10-19 07:27:19 +04:00
}
2011-11-22 00:32:22 +04:00
EXPORT_SYMBOL ( __refrigerator ) ;
2008-10-19 07:27:19 +04:00
static void fake_signal_wake_up ( struct task_struct * p )
{
unsigned long flags ;
2011-11-22 00:32:26 +04:00
if ( lock_task_sighand ( p , & flags ) ) {
signal_wake_up ( p , 0 ) ;
unlock_task_sighand ( p , & flags ) ;
}
2008-10-19 07:27:19 +04:00
}
/**
2011-11-22 00:32:26 +04:00
* freeze_task - send a freeze request to given task
* @ p : task to send the request to
2008-10-19 07:27:19 +04:00
*
2012-02-22 02:57:47 +04:00
* If @ p is freezing , the freeze request is sent either by sending a fake
* signal ( if it ' s not a kernel thread ) or waking it up ( if it ' s a kernel
* thread ) .
2011-11-22 00:32:26 +04:00
*
* RETURNS :
* % false , if @ p is not freezing or already frozen ; % true , otherwise
2008-10-19 07:27:19 +04:00
*/
2011-11-22 00:32:26 +04:00
bool freeze_task ( struct task_struct * p )
2008-10-19 07:27:19 +04:00
{
2011-11-22 00:32:24 +04:00
unsigned long flags ;
2013-05-07 03:50:11 +04:00
/*
* This check can race with freezer_do_not_count , but worst case that
* will result in an extra wakeup being sent to the task . It does not
* race with freezer_count ( ) , the barriers in freezer_count ( ) and
* freezer_should_skip ( ) ensure that either freezer_count ( ) sees
* freezing = = true in try_to_freeze ( ) and freezes , or
* freezer_should_skip ( ) sees ! PF_FREEZE_SKIP and freezes the task
* normally .
*/
if ( freezer_should_skip ( p ) )
return false ;
2011-11-22 00:32:24 +04:00
spin_lock_irqsave ( & freezer_lock , flags ) ;
2011-11-22 00:32:25 +04:00
if ( ! freezing ( p ) | | frozen ( p ) ) {
spin_unlock_irqrestore ( & freezer_lock , flags ) ;
return false ;
}
2008-10-19 07:27:19 +04:00
2012-10-26 21:46:06 +04:00
if ( ! ( p - > flags & PF_KTHREAD ) )
2010-11-27 01:07:27 +03:00
fake_signal_wake_up ( p ) ;
2012-10-26 21:46:06 +04:00
else
2008-10-19 07:27:19 +04:00
wake_up_state ( p , TASK_INTERRUPTIBLE ) ;
2011-11-22 00:32:25 +04:00
2011-11-22 00:32:24 +04:00
spin_unlock_irqrestore ( & freezer_lock , flags ) ;
2011-11-22 00:32:25 +04:00
return true ;
2008-10-19 07:27:19 +04:00
}
2011-11-22 00:32:23 +04:00
void __thaw_task ( struct task_struct * p )
2008-10-19 07:27:21 +04:00
{
2011-11-22 00:32:24 +04:00
unsigned long flags ;
2011-11-22 00:32:23 +04:00
2011-11-22 00:32:24 +04:00
spin_lock_irqsave ( & freezer_lock , flags ) ;
2011-11-23 21:28:17 +04:00
if ( frozen ( p ) )
2011-11-22 00:32:23 +04:00
wake_up_process ( p ) ;
2011-11-22 00:32:24 +04:00
spin_unlock_irqrestore ( & freezer_lock , flags ) ;
2008-10-19 07:27:21 +04:00
}
2011-11-22 00:32:25 +04:00
/**
2011-11-23 21:28:17 +04:00
* set_freezable - make % current freezable
2011-11-22 00:32:25 +04:00
*
* Mark % current freezable and enter refrigerator if necessary .
*/
2011-11-23 21:28:17 +04:00
bool set_freezable ( void )
2011-11-22 00:32:25 +04:00
{
might_sleep ( ) ;
/*
* Modify flags while holding freezer_lock . This ensures the
* freezer notices that we aren ' t frozen yet or the freezing
* condition is visible to try_to_freeze ( ) below .
*/
spin_lock_irq ( & freezer_lock ) ;
current - > flags & = ~ PF_NOFREEZE ;
spin_unlock_irq ( & freezer_lock ) ;
return try_to_freeze ( ) ;
}
2011-11-23 21:28:17 +04:00
EXPORT_SYMBOL ( set_freezable ) ;