1
2
3
4
5
6
7
8#include <linux/interrupt.h>
9#include <linux/suspend.h>
10#include <linux/export.h>
11#include <linux/syscalls.h>
12#include <linux/freezer.h>
13#include <linux/kthread.h>
14
15
16atomic_t system_freezing_cnt = ATOMIC_INIT(0);
17EXPORT_SYMBOL(system_freezing_cnt);
18
19
20
21
22bool pm_freezing;
23bool pm_nosig_freezing;
24
25
26
27
28
29EXPORT_SYMBOL_GPL(pm_freezing);
30
31
32static DEFINE_SPINLOCK(freezer_lock);
33
34
35
36
37
38
39
40
41
42
43bool freezing_slow_path(struct task_struct *p)
44{
45 if (p->flags & (PF_NOFREEZE | PF_SUSPEND_TASK))
46 return false;
47
48 if (test_tsk_thread_flag(p, TIF_MEMDIE))
49 return false;
50
51 if (pm_nosig_freezing || cgroup_freezing(p))
52 return true;
53
54 if (pm_freezing && !(p->flags & PF_KTHREAD))
55 return true;
56
57 return false;
58}
59EXPORT_SYMBOL(freezing_slow_path);
60
61
62bool __refrigerator(bool check_kthr_stop)
63{
64
65
66 bool was_frozen = false;
67 long save = current->state;
68
69 pr_debug("%s entered refrigerator\n", current->comm);
70
71 for (;;) {
72 set_current_state(TASK_UNINTERRUPTIBLE);
73
74 spin_lock_irq(&freezer_lock);
75 current->flags |= PF_FROZEN;
76 if (!freezing(current) ||
77 (check_kthr_stop && kthread_should_stop()))
78 current->flags &= ~PF_FROZEN;
79 spin_unlock_irq(&freezer_lock);
80
81 if (!(current->flags & PF_FROZEN))
82 break;
83 was_frozen = true;
84 schedule();
85 }
86
87 pr_debug("%s left refrigerator\n", current->comm);
88
89
90
91
92
93
94 set_current_state(save);
95
96 return was_frozen;
97}
98EXPORT_SYMBOL(__refrigerator);
99
100static void fake_signal_wake_up(struct task_struct *p)
101{
102 unsigned long flags;
103
104 if (lock_task_sighand(p, &flags)) {
105 signal_wake_up(p, 0);
106 unlock_task_sighand(p, &flags);
107 }
108}
109
110
111
112
113
114
115
116
117
118
119
120
121bool freeze_task(struct task_struct *p)
122{
123 unsigned long flags;
124
125
126
127
128
129
130
131
132
133
134 if (freezer_should_skip(p))
135 return false;
136
137 spin_lock_irqsave(&freezer_lock, flags);
138 if (!freezing(p) || frozen(p)) {
139 spin_unlock_irqrestore(&freezer_lock, flags);
140 return false;
141 }
142
143 if (!(p->flags & PF_KTHREAD))
144 fake_signal_wake_up(p);
145 else
146 wake_up_state(p, TASK_INTERRUPTIBLE);
147
148 spin_unlock_irqrestore(&freezer_lock, flags);
149 return true;
150}
151
152void __thaw_task(struct task_struct *p)
153{
154 unsigned long flags;
155
156 spin_lock_irqsave(&freezer_lock, flags);
157 if (frozen(p))
158 wake_up_process(p);
159 spin_unlock_irqrestore(&freezer_lock, flags);
160}
161
162
163
164
165
166
167bool set_freezable(void)
168{
169 might_sleep();
170
171
172
173
174
175
176 spin_lock_irq(&freezer_lock);
177 current->flags &= ~PF_NOFREEZE;
178 spin_unlock_irq(&freezer_lock);
179
180 return try_to_freeze();
181}
182EXPORT_SYMBOL(set_freezable);
183