296699de6b
Introduce CONFIG_SUSPEND representing the ability to enter system sleep states, such as the ACPI S3 state, and allow the user to choose SUSPEND and HIBERNATION independently of each other. Make HOTPLUG_CPU be selected automatically if SUSPEND or HIBERNATION has been chosen and the kernel is intended for SMP systems. Also, introduce CONFIG_PM_SLEEP which is automatically selected if CONFIG_SUSPEND or CONFIG_HIBERNATION is set and use it to select the code needed for both suspend and hibernation. The top-level power management headers and the ACPI code related to suspend and hibernation are modified to use the new definitions (the changes in drivers/acpi/sleep/main.c are, mostly, moving code to reduce the number of ifdefs). There are many other files in which CONFIG_PM can be replaced with CONFIG_PM_SLEEP or even with CONFIG_SUSPEND, but they can be updated in the future. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
148 lines
3.9 KiB
C++
148 lines
3.9 KiB
C++
/* Freezer declarations */
|
|
|
|
#ifndef FREEZER_H_INCLUDED
|
|
#define FREEZER_H_INCLUDED
|
|
|
|
#include <linux/sched.h>
|
|
|
|
#ifdef CONFIG_PM_SLEEP
|
|
/*
|
|
* Check if a process has been frozen
|
|
*/
|
|
static inline int frozen(struct task_struct *p)
|
|
{
|
|
return p->flags & PF_FROZEN;
|
|
}
|
|
|
|
/*
|
|
* Check if there is a request to freeze a process
|
|
*/
|
|
static inline int freezing(struct task_struct *p)
|
|
{
|
|
return test_tsk_thread_flag(p, TIF_FREEZE);
|
|
}
|
|
|
|
/*
|
|
* Request that a process be frozen
|
|
*/
|
|
static inline void set_freeze_flag(struct task_struct *p)
|
|
{
|
|
set_tsk_thread_flag(p, TIF_FREEZE);
|
|
}
|
|
|
|
/*
|
|
* Sometimes we may need to cancel the previous 'freeze' request
|
|
*/
|
|
static inline void clear_freeze_flag(struct task_struct *p)
|
|
{
|
|
clear_tsk_thread_flag(p, TIF_FREEZE);
|
|
}
|
|
|
|
/*
|
|
* Wake up a frozen process
|
|
*
|
|
* task_lock() is taken to prevent the race with refrigerator() which may
|
|
* occur if the freezing of tasks fails. Namely, without the lock, if the
|
|
* freezing of tasks failed, thaw_tasks() might have run before a task in
|
|
* refrigerator() could call frozen_process(), in which case the task would be
|
|
* frozen and no one would thaw it.
|
|
*/
|
|
static inline int thaw_process(struct task_struct *p)
|
|
{
|
|
task_lock(p);
|
|
if (frozen(p)) {
|
|
p->flags &= ~PF_FROZEN;
|
|
task_unlock(p);
|
|
wake_up_process(p);
|
|
return 1;
|
|
}
|
|
clear_freeze_flag(p);
|
|
task_unlock(p);
|
|
return 0;
|
|
}
|
|
|
|
extern void refrigerator(void);
|
|
extern int freeze_processes(void);
|
|
extern void thaw_processes(void);
|
|
|
|
static inline int try_to_freeze(void)
|
|
{
|
|
if (freezing(current)) {
|
|
refrigerator();
|
|
return 1;
|
|
} else
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* The PF_FREEZER_SKIP flag should be set by a vfork parent right before it
|
|
* calls wait_for_completion(&vfork) and reset right after it returns from this
|
|
* function. Next, the parent should call try_to_freeze() to freeze itself
|
|
* appropriately in case the child has exited before the freezing of tasks is
|
|
* complete. However, we don't want kernel threads to be frozen in unexpected
|
|
* places, so we allow them to block freeze_processes() instead or to set
|
|
* PF_NOFREEZE if needed and PF_FREEZER_SKIP is only set for userland vfork
|
|
* parents. Fortunately, in the ____call_usermodehelper() case the parent won't
|
|
* really block freeze_processes(), since ____call_usermodehelper() (the child)
|
|
* does a little before exec/exit and it can't be frozen before waking up the
|
|
* parent.
|
|
*/
|
|
|
|
/*
|
|
* If the current task is a user space one, tell the freezer not to count it as
|
|
* freezable.
|
|
*/
|
|
static inline void freezer_do_not_count(void)
|
|
{
|
|
if (current->mm)
|
|
current->flags |= PF_FREEZER_SKIP;
|
|
}
|
|
|
|
/*
|
|
* If the current task is a user space one, tell the freezer to count it as
|
|
* freezable again and try to freeze it.
|
|
*/
|
|
static inline void freezer_count(void)
|
|
{
|
|
if (current->mm) {
|
|
current->flags &= ~PF_FREEZER_SKIP;
|
|
try_to_freeze();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check if the task should be counted as freezeable by the freezer
|
|
*/
|
|
static inline int freezer_should_skip(struct task_struct *p)
|
|
{
|
|
return !!(p->flags & PF_FREEZER_SKIP);
|
|
}
|
|
|
|
/*
|
|
* Tell the freezer that the current task should be frozen by it
|
|
*/
|
|
static inline void set_freezable(void)
|
|
{
|
|
current->flags &= ~PF_NOFREEZE;
|
|
}
|
|
|
|
#else /* !CONFIG_PM_SLEEP */
|
|
static inline int frozen(struct task_struct *p) { return 0; }
|
|
static inline int freezing(struct task_struct *p) { return 0; }
|
|
static inline void set_freeze_flag(struct task_struct *p) {}
|
|
static inline void clear_freeze_flag(struct task_struct *p) {}
|
|
static inline int thaw_process(struct task_struct *p) { return 1; }
|
|
|
|
static inline void refrigerator(void) {}
|
|
static inline int freeze_processes(void) { BUG(); return 0; }
|
|
static inline void thaw_processes(void) {}
|
|
|
|
static inline int try_to_freeze(void) { return 0; }
|
|
|
|
static inline void freezer_do_not_count(void) {}
|
|
static inline void freezer_count(void) {}
|
|
static inline int freezer_should_skip(struct task_struct *p) { return 0; }
|
|
static inline void set_freezable(void) {}
|
|
#endif /* !CONFIG_PM_SLEEP */
|
|
|
|
#endif /* FREEZER_H_INCLUDED */
|