Root/kernel/freezer.c

1/*
2 * kernel/freezer.c - Function to freeze a process
3 *
4 * Originally from kernel/power/process.c
5 */
6
7#include <linux/interrupt.h>
8#include <linux/suspend.h>
9#include <linux/export.h>
10#include <linux/syscalls.h>
11#include <linux/freezer.h>
12#include <linux/kthread.h>
13
14/* total number of freezing conditions in effect */
15atomic_t system_freezing_cnt = ATOMIC_INIT(0);
16EXPORT_SYMBOL(system_freezing_cnt);
17
18/* indicate whether PM freezing is in effect, protected by pm_mutex */
19bool pm_freezing;
20bool pm_nosig_freezing;
21
22/* protects freezing and frozen transitions */
23static DEFINE_SPINLOCK(freezer_lock);
24
25/**
26 * freezing_slow_path - slow path for testing whether a task needs to be frozen
27 * @p: task to be tested
28 *
29 * This function is called by freezing() if system_freezing_cnt isn't zero
30 * and tests whether @p needs to enter and stay in frozen state. Can be
31 * called under any context. The freezers are responsible for ensuring the
32 * target tasks see the updated state.
33 */
34bool freezing_slow_path(struct task_struct *p)
35{
36    if (p->flags & PF_NOFREEZE)
37        return false;
38
39    if (pm_nosig_freezing || cgroup_freezing(p))
40        return true;
41
42    if (pm_freezing && !(p->flags & PF_KTHREAD))
43        return true;
44
45    return false;
46}
47EXPORT_SYMBOL(freezing_slow_path);
48
49/* Refrigerator is place where frozen processes are stored :-). */
50bool __refrigerator(bool check_kthr_stop)
51{
52    /* Hmm, should we be allowed to suspend when there are realtime
53       processes around? */
54    bool was_frozen = false;
55    long save = current->state;
56
57    pr_debug("%s entered refrigerator\n", current->comm);
58
59    for (;;) {
60        set_current_state(TASK_UNINTERRUPTIBLE);
61
62        spin_lock_irq(&freezer_lock);
63        current->flags |= PF_FROZEN;
64        if (!freezing(current) ||
65            (check_kthr_stop && kthread_should_stop()))
66            current->flags &= ~PF_FROZEN;
67        spin_unlock_irq(&freezer_lock);
68
69        if (!(current->flags & PF_FROZEN))
70            break;
71        was_frozen = true;
72        schedule();
73    }
74
75    pr_debug("%s left refrigerator\n", current->comm);
76
77    /*
78     * Restore saved task state before returning. The mb'd version
79     * needs to be used; otherwise, it might silently break
80     * synchronization which depends on ordered task state change.
81     */
82    set_current_state(save);
83
84    return was_frozen;
85}
86EXPORT_SYMBOL(__refrigerator);
87
88static void fake_signal_wake_up(struct task_struct *p)
89{
90    unsigned long flags;
91
92    if (lock_task_sighand(p, &flags)) {
93        signal_wake_up(p, 0);
94        unlock_task_sighand(p, &flags);
95    }
96}
97
98/**
99 * freeze_task - send a freeze request to given task
100 * @p: task to send the request to
101 *
102 * If @p is freezing, the freeze request is sent either by sending a fake
103 * signal (if it's not a kernel thread) or waking it up (if it's a kernel
104 * thread).
105 *
106 * RETURNS:
107 * %false, if @p is not freezing or already frozen; %true, otherwise
108 */
109bool freeze_task(struct task_struct *p)
110{
111    unsigned long flags;
112
113    spin_lock_irqsave(&freezer_lock, flags);
114    if (!freezing(p) || frozen(p)) {
115        spin_unlock_irqrestore(&freezer_lock, flags);
116        return false;
117    }
118
119    if (!(p->flags & PF_KTHREAD)) {
120        fake_signal_wake_up(p);
121        /*
122         * fake_signal_wake_up() goes through p's scheduler
123         * lock and guarantees that TASK_STOPPED/TRACED ->
124         * TASK_RUNNING transition can't race with task state
125         * testing in try_to_freeze_tasks().
126         */
127    } else {
128        wake_up_state(p, TASK_INTERRUPTIBLE);
129    }
130
131    spin_unlock_irqrestore(&freezer_lock, flags);
132    return true;
133}
134
135void __thaw_task(struct task_struct *p)
136{
137    unsigned long flags;
138
139    /*
140     * Clear freezing and kick @p if FROZEN. Clearing is guaranteed to
141     * be visible to @p as waking up implies wmb. Waking up inside
142     * freezer_lock also prevents wakeups from leaking outside
143     * refrigerator.
144     */
145    spin_lock_irqsave(&freezer_lock, flags);
146    if (frozen(p))
147        wake_up_process(p);
148    spin_unlock_irqrestore(&freezer_lock, flags);
149}
150
151/**
152 * set_freezable - make %current freezable
153 *
154 * Mark %current freezable and enter refrigerator if necessary.
155 */
156bool set_freezable(void)
157{
158    might_sleep();
159
160    /*
161     * Modify flags while holding freezer_lock. This ensures the
162     * freezer notices that we aren't frozen yet or the freezing
163     * condition is visible to try_to_freeze() below.
164     */
165    spin_lock_irq(&freezer_lock);
166    current->flags &= ~PF_NOFREEZE;
167    spin_unlock_irq(&freezer_lock);
168
169    return try_to_freeze();
170}
171EXPORT_SYMBOL(set_freezable);
172

Archive Download this file



interactive