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