mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 03:36:19 +00:00
container freezer: make refrigerator always available
Now that the TIF_FREEZE flag is available in all architectures, extract the refrigerator() and freeze_task() from kernel/power/process.c and make it available to all. The refrigerator() can now be used in a control group subsystem implementing a control group freezer. Signed-off-by: Cedric Le Goater <clg@fr.ibm.com> Signed-off-by: Matt Helsley <matthltc@us.ibm.com> Acked-by: Serge E. Hallyn <serue@us.ibm.com> Tested-by: Matt Helsley <matthltc@us.ibm.com> Cc: "Rafael J. Wysocki" <rjw@sisk.pl> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
83224b0837
commit
8174f1503f
5 changed files with 137 additions and 119 deletions
|
@ -6,7 +6,7 @@
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/wait.h>
|
#include <linux/wait.h>
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_FREEZER
|
||||||
/*
|
/*
|
||||||
* Check if a process has been frozen
|
* Check if a process has been frozen
|
||||||
*/
|
*/
|
||||||
|
@ -39,6 +39,11 @@ static inline void clear_freeze_flag(struct task_struct *p)
|
||||||
clear_tsk_thread_flag(p, TIF_FREEZE);
|
clear_tsk_thread_flag(p, TIF_FREEZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool should_send_signal(struct task_struct *p)
|
||||||
|
{
|
||||||
|
return !(p->flags & PF_FREEZER_NOSIG);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wake up a frozen process
|
* Wake up a frozen process
|
||||||
*
|
*
|
||||||
|
@ -75,6 +80,9 @@ static inline int try_to_freeze(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern bool freeze_task(struct task_struct *p, bool sig_only);
|
||||||
|
extern void cancel_freezing(struct task_struct *p);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The PF_FREEZER_SKIP flag should be set by a vfork parent right before it
|
* 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
|
* calls wait_for_completion(&vfork) and reset right after it returns from this
|
||||||
|
@ -166,7 +174,7 @@ static inline void set_freezable_with_signal(void)
|
||||||
} while (try_to_freeze()); \
|
} while (try_to_freeze()); \
|
||||||
__retval; \
|
__retval; \
|
||||||
})
|
})
|
||||||
#else /* !CONFIG_PM_SLEEP */
|
#else /* !CONFIG_FREEZER */
|
||||||
static inline int frozen(struct task_struct *p) { return 0; }
|
static inline int frozen(struct task_struct *p) { return 0; }
|
||||||
static inline int freezing(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 set_freeze_flag(struct task_struct *p) {}
|
||||||
|
@ -191,6 +199,6 @@ static inline void set_freezable_with_signal(void) {}
|
||||||
#define wait_event_freezable_timeout(wq, condition, timeout) \
|
#define wait_event_freezable_timeout(wq, condition, timeout) \
|
||||||
wait_event_interruptible_timeout(wq, condition, timeout)
|
wait_event_interruptible_timeout(wq, condition, timeout)
|
||||||
|
|
||||||
#endif /* !CONFIG_PM_SLEEP */
|
#endif /* !CONFIG_FREEZER */
|
||||||
|
|
||||||
#endif /* FREEZER_H_INCLUDED */
|
#endif /* FREEZER_H_INCLUDED */
|
||||||
|
|
|
@ -24,6 +24,7 @@ CFLAGS_REMOVE_sched_clock.o = -pg
|
||||||
CFLAGS_REMOVE_sched.o = -mno-spe -pg
|
CFLAGS_REMOVE_sched.o = -mno-spe -pg
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
obj-$(CONFIG_FREEZER) += freezer.o
|
||||||
obj-$(CONFIG_PROFILING) += profile.o
|
obj-$(CONFIG_PROFILING) += profile.o
|
||||||
obj-$(CONFIG_SYSCTL_SYSCALL_CHECK) += sysctl_check.o
|
obj-$(CONFIG_SYSCTL_SYSCALL_CHECK) += sysctl_check.o
|
||||||
obj-$(CONFIG_STACKTRACE) += stacktrace.o
|
obj-$(CONFIG_STACKTRACE) += stacktrace.o
|
||||||
|
|
122
kernel/freezer.c
Normal file
122
kernel/freezer.c
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* kernel/freezer.c - Function to freeze a process
|
||||||
|
*
|
||||||
|
* Originally from kernel/power/process.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/suspend.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/syscalls.h>
|
||||||
|
#include <linux/freezer.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* freezing is complete, mark current process as frozen
|
||||||
|
*/
|
||||||
|
static inline void frozen_process(void)
|
||||||
|
{
|
||||||
|
if (!unlikely(current->flags & PF_NOFREEZE)) {
|
||||||
|
current->flags |= PF_FROZEN;
|
||||||
|
wmb();
|
||||||
|
}
|
||||||
|
clear_freeze_flag(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Refrigerator is place where frozen processes are stored :-). */
|
||||||
|
void refrigerator(void)
|
||||||
|
{
|
||||||
|
/* Hmm, should we be allowed to suspend when there are realtime
|
||||||
|
processes around? */
|
||||||
|
long save;
|
||||||
|
|
||||||
|
task_lock(current);
|
||||||
|
if (freezing(current)) {
|
||||||
|
frozen_process();
|
||||||
|
task_unlock(current);
|
||||||
|
} else {
|
||||||
|
task_unlock(current);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
save = current->state;
|
||||||
|
pr_debug("%s entered refrigerator\n", current->comm);
|
||||||
|
|
||||||
|
spin_lock_irq(¤t->sighand->siglock);
|
||||||
|
recalc_sigpending(); /* We sent fake signal, clean it up */
|
||||||
|
spin_unlock_irq(¤t->sighand->siglock);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||||
|
if (!frozen(current))
|
||||||
|
break;
|
||||||
|
schedule();
|
||||||
|
}
|
||||||
|
pr_debug("%s left refrigerator\n", current->comm);
|
||||||
|
__set_current_state(save);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(refrigerator);
|
||||||
|
|
||||||
|
static void fake_signal_wake_up(struct task_struct *p)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&p->sighand->siglock, flags);
|
||||||
|
signal_wake_up(p, 0);
|
||||||
|
spin_unlock_irqrestore(&p->sighand->siglock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* freeze_task - send a freeze request to given task
|
||||||
|
* @p: task to send the request to
|
||||||
|
* @sig_only: if set, the request will only be sent if the task has the
|
||||||
|
* PF_FREEZER_NOSIG flag unset
|
||||||
|
* Return value: 'false', if @sig_only is set and the task has
|
||||||
|
* PF_FREEZER_NOSIG set or the task is frozen, 'true', otherwise
|
||||||
|
*
|
||||||
|
* The freeze request is sent by setting the tasks's TIF_FREEZE flag and
|
||||||
|
* either sending a fake signal to it or waking it up, depending on whether
|
||||||
|
* or not it has PF_FREEZER_NOSIG set. If @sig_only is set and the task
|
||||||
|
* has PF_FREEZER_NOSIG set (ie. it is a typical kernel thread), its
|
||||||
|
* TIF_FREEZE flag will not be set.
|
||||||
|
*/
|
||||||
|
bool freeze_task(struct task_struct *p, bool sig_only)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We first check if the task is freezing and next if it has already
|
||||||
|
* been frozen to avoid the race with frozen_process() which first marks
|
||||||
|
* the task as frozen and next clears its TIF_FREEZE.
|
||||||
|
*/
|
||||||
|
if (!freezing(p)) {
|
||||||
|
rmb();
|
||||||
|
if (frozen(p))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!sig_only || should_send_signal(p))
|
||||||
|
set_freeze_flag(p);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (should_send_signal(p)) {
|
||||||
|
if (!signal_pending(p))
|
||||||
|
fake_signal_wake_up(p);
|
||||||
|
} else if (sig_only) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
wake_up_state(p, TASK_INTERRUPTIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cancel_freezing(struct task_struct *p)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
if (freezing(p)) {
|
||||||
|
pr_debug(" clean up: %s\n", p->comm);
|
||||||
|
clear_freeze_flag(p);
|
||||||
|
spin_lock_irqsave(&p->sighand->siglock, flags);
|
||||||
|
recalc_sigpending_and_wake(p);
|
||||||
|
spin_unlock_irqrestore(&p->sighand->siglock, flags);
|
||||||
|
}
|
||||||
|
}
|
|
@ -85,6 +85,9 @@ config PM_SLEEP
|
||||||
depends on SUSPEND || HIBERNATION || XEN_SAVE_RESTORE
|
depends on SUSPEND || HIBERNATION || XEN_SAVE_RESTORE
|
||||||
default y
|
default y
|
||||||
|
|
||||||
|
config FREEZER
|
||||||
|
def_bool PM_SLEEP
|
||||||
|
|
||||||
config SUSPEND
|
config SUSPEND
|
||||||
bool "Suspend to RAM and standby"
|
bool "Suspend to RAM and standby"
|
||||||
depends on PM && ARCH_SUSPEND_POSSIBLE
|
depends on PM && ARCH_SUSPEND_POSSIBLE
|
||||||
|
|
|
@ -28,121 +28,6 @@ static inline int freezeable(struct task_struct * p)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* freezing is complete, mark current process as frozen
|
|
||||||
*/
|
|
||||||
static inline void frozen_process(void)
|
|
||||||
{
|
|
||||||
if (!unlikely(current->flags & PF_NOFREEZE)) {
|
|
||||||
current->flags |= PF_FROZEN;
|
|
||||||
wmb();
|
|
||||||
}
|
|
||||||
clear_freeze_flag(current);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Refrigerator is place where frozen processes are stored :-). */
|
|
||||||
void refrigerator(void)
|
|
||||||
{
|
|
||||||
/* Hmm, should we be allowed to suspend when there are realtime
|
|
||||||
processes around? */
|
|
||||||
long save;
|
|
||||||
|
|
||||||
task_lock(current);
|
|
||||||
if (freezing(current)) {
|
|
||||||
frozen_process();
|
|
||||||
task_unlock(current);
|
|
||||||
} else {
|
|
||||||
task_unlock(current);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
save = current->state;
|
|
||||||
pr_debug("%s entered refrigerator\n", current->comm);
|
|
||||||
|
|
||||||
spin_lock_irq(¤t->sighand->siglock);
|
|
||||||
recalc_sigpending(); /* We sent fake signal, clean it up */
|
|
||||||
spin_unlock_irq(¤t->sighand->siglock);
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
|
||||||
if (!frozen(current))
|
|
||||||
break;
|
|
||||||
schedule();
|
|
||||||
}
|
|
||||||
pr_debug("%s left refrigerator\n", current->comm);
|
|
||||||
__set_current_state(save);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fake_signal_wake_up(struct task_struct *p)
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&p->sighand->siglock, flags);
|
|
||||||
signal_wake_up(p, 0);
|
|
||||||
spin_unlock_irqrestore(&p->sighand->siglock, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool should_send_signal(struct task_struct *p)
|
|
||||||
{
|
|
||||||
return !(p->flags & PF_FREEZER_NOSIG);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* freeze_task - send a freeze request to given task
|
|
||||||
* @p: task to send the request to
|
|
||||||
* @sig_only: if set, the request will only be sent if the task has the
|
|
||||||
* PF_FREEZER_NOSIG flag unset
|
|
||||||
* Return value: 'false', if @sig_only is set and the task has
|
|
||||||
* PF_FREEZER_NOSIG set or the task is frozen, 'true', otherwise
|
|
||||||
*
|
|
||||||
* The freeze request is sent by setting the tasks's TIF_FREEZE flag and
|
|
||||||
* either sending a fake signal to it or waking it up, depending on whether
|
|
||||||
* or not it has PF_FREEZER_NOSIG set. If @sig_only is set and the task
|
|
||||||
* has PF_FREEZER_NOSIG set (ie. it is a typical kernel thread), its
|
|
||||||
* TIF_FREEZE flag will not be set.
|
|
||||||
*/
|
|
||||||
static bool freeze_task(struct task_struct *p, bool sig_only)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* We first check if the task is freezing and next if it has already
|
|
||||||
* been frozen to avoid the race with frozen_process() which first marks
|
|
||||||
* the task as frozen and next clears its TIF_FREEZE.
|
|
||||||
*/
|
|
||||||
if (!freezing(p)) {
|
|
||||||
rmb();
|
|
||||||
if (frozen(p))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!sig_only || should_send_signal(p))
|
|
||||||
set_freeze_flag(p);
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (should_send_signal(p)) {
|
|
||||||
if (!signal_pending(p))
|
|
||||||
fake_signal_wake_up(p);
|
|
||||||
} else if (sig_only) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
wake_up_state(p, TASK_INTERRUPTIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cancel_freezing(struct task_struct *p)
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (freezing(p)) {
|
|
||||||
pr_debug(" clean up: %s\n", p->comm);
|
|
||||||
clear_freeze_flag(p);
|
|
||||||
spin_lock_irqsave(&p->sighand->siglock, flags);
|
|
||||||
recalc_sigpending_and_wake(p);
|
|
||||||
spin_unlock_irqrestore(&p->sighand->siglock, flags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int try_to_freeze_tasks(bool sig_only)
|
static int try_to_freeze_tasks(bool sig_only)
|
||||||
{
|
{
|
||||||
struct task_struct *g, *p;
|
struct task_struct *g, *p;
|
||||||
|
@ -264,4 +149,3 @@ void thaw_processes(void)
|
||||||
printk("done.\n");
|
printk("done.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(refrigerator);
|
|
||||||
|
|
Loading…
Reference in a new issue