Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * drivers/power/process.c - Functions for starting/stopping processes on | |
3 | * suspend transitions. | |
4 | * | |
5 | * Originally from swsusp. | |
6 | */ | |
7 | ||
8 | ||
9 | #undef DEBUG | |
10 | ||
1da177e4 | 11 | #include <linux/interrupt.h> |
1a8670a2 | 12 | #include <linux/oom.h> |
1da177e4 LT |
13 | #include <linux/suspend.h> |
14 | #include <linux/module.h> | |
02aaeb9b | 15 | #include <linux/syscalls.h> |
7dfb7103 | 16 | #include <linux/freezer.h> |
be404f02 | 17 | #include <linux/delay.h> |
a0a1a5fd | 18 | #include <linux/workqueue.h> |
1da177e4 LT |
19 | |
20 | /* | |
21 | * Timeout for stopping processes | |
22 | */ | |
02aaeb9b | 23 | #define TIMEOUT (20 * HZ) |
1da177e4 | 24 | |
839e3407 | 25 | static int try_to_freeze_tasks(bool user_only) |
1da177e4 | 26 | { |
1da177e4 | 27 | struct task_struct *g, *p; |
11b2ce2b RW |
28 | unsigned long end_time; |
29 | unsigned int todo; | |
a0a1a5fd | 30 | bool wq_busy = false; |
438e2ce6 | 31 | struct timeval start, end; |
f0af566d | 32 | u64 elapsed_csecs64; |
438e2ce6 | 33 | unsigned int elapsed_csecs; |
dbeeec5f | 34 | bool wakeup = false; |
438e2ce6 RW |
35 | |
36 | do_gettimeofday(&start); | |
3e1d1d28 | 37 | |
11b2ce2b | 38 | end_time = jiffies + TIMEOUT; |
a0a1a5fd | 39 | |
839e3407 | 40 | if (!user_only) |
a0a1a5fd TH |
41 | freeze_workqueues_begin(); |
42 | ||
be404f02 | 43 | while (true) { |
11b2ce2b | 44 | todo = 0; |
1da177e4 LT |
45 | read_lock(&tasklist_lock); |
46 | do_each_thread(g, p) { | |
839e3407 | 47 | if (p == current || !freeze_task(p)) |
d5d8c597 RW |
48 | continue; |
49 | ||
13b1c3d4 RM |
50 | /* |
51 | * Now that we've done set_freeze_flag, don't | |
52 | * perturb a task in TASK_STOPPED or TASK_TRACED. | |
53 | * It is "frozen enough". If the task does wake | |
54 | * up, it will immediately call try_to_freeze. | |
8cfe400c | 55 | * |
37f08be1 MPS |
56 | * Because freeze_task() goes through p's scheduler lock, it's |
57 | * guaranteed that TASK_STOPPED/TRACED -> TASK_RUNNING | |
58 | * transition can't race with task state testing here. | |
13b1c3d4 RM |
59 | */ |
60 | if (!task_is_stopped_or_traced(p) && | |
61 | !freezer_should_skip(p)) | |
ba96a0c8 | 62 | todo++; |
1da177e4 LT |
63 | } while_each_thread(g, p); |
64 | read_unlock(&tasklist_lock); | |
a0a1a5fd | 65 | |
839e3407 | 66 | if (!user_only) { |
a0a1a5fd TH |
67 | wq_busy = freeze_workqueues_busy(); |
68 | todo += wq_busy; | |
69 | } | |
70 | ||
be404f02 | 71 | if (!todo || time_after(jiffies, end_time)) |
6161b2ce | 72 | break; |
be404f02 | 73 | |
a2867e08 | 74 | if (pm_wakeup_pending()) { |
dbeeec5f RW |
75 | wakeup = true; |
76 | break; | |
77 | } | |
78 | ||
be404f02 TH |
79 | /* |
80 | * We need to retry, but first give the freezing tasks some | |
81 | * time to enter the regrigerator. | |
82 | */ | |
83 | msleep(10); | |
84 | } | |
3e1d1d28 | 85 | |
438e2ce6 RW |
86 | do_gettimeofday(&end); |
87 | elapsed_csecs64 = timeval_to_ns(&end) - timeval_to_ns(&start); | |
88 | do_div(elapsed_csecs64, NSEC_PER_SEC / 100); | |
89 | elapsed_csecs = elapsed_csecs64; | |
90 | ||
6161b2ce | 91 | if (todo) { |
14b5b7cf | 92 | printk("\n"); |
dbeeec5f | 93 | printk(KERN_ERR "Freezing of tasks %s after %d.%02d seconds " |
a0a1a5fd | 94 | "(%d tasks refusing to freeze, wq_busy=%d):\n", |
dbeeec5f | 95 | wakeup ? "aborted" : "failed", |
a0a1a5fd TH |
96 | elapsed_csecs / 100, elapsed_csecs % 100, |
97 | todo - wq_busy, wq_busy); | |
98 | ||
6c83b481 RW |
99 | if (!wakeup) { |
100 | read_lock(&tasklist_lock); | |
101 | do_each_thread(g, p) { | |
102 | if (p != current && !freezer_should_skip(p) | |
103 | && freezing(p) && !frozen(p)) | |
104 | sched_show_task(p); | |
105 | } while_each_thread(g, p); | |
106 | read_unlock(&tasklist_lock); | |
107 | } | |
438e2ce6 RW |
108 | } else { |
109 | printk("(elapsed %d.%02d seconds) ", elapsed_csecs / 100, | |
110 | elapsed_csecs % 100); | |
6161b2ce PM |
111 | } |
112 | ||
e7cd8a72 | 113 | return todo ? -EBUSY : 0; |
11b2ce2b RW |
114 | } |
115 | ||
116 | /** | |
2aede851 | 117 | * freeze_processes - Signal user space processes to enter the refrigerator. |
03afed8b TH |
118 | * |
119 | * On success, returns 0. On failure, -errno and system is fully thawed. | |
11b2ce2b RW |
120 | */ |
121 | int freeze_processes(void) | |
122 | { | |
e7cd8a72 | 123 | int error; |
11b2ce2b | 124 | |
a3201227 TH |
125 | if (!pm_freezing) |
126 | atomic_inc(&system_freezing_cnt); | |
127 | ||
b842ee57 | 128 | printk("Freezing user space processes ... "); |
a3201227 | 129 | pm_freezing = true; |
ebb12db5 | 130 | error = try_to_freeze_tasks(true); |
2aede851 RW |
131 | if (!error) { |
132 | printk("done."); | |
133 | oom_killer_disable(); | |
134 | } | |
135 | printk("\n"); | |
136 | BUG_ON(in_atomic()); | |
137 | ||
03afed8b TH |
138 | if (error) |
139 | thaw_processes(); | |
2aede851 RW |
140 | return error; |
141 | } | |
142 | ||
143 | /** | |
144 | * freeze_kernel_threads - Make freezable kernel threads go to the refrigerator. | |
03afed8b | 145 | * |
379e0be8 SB |
146 | * On success, returns 0. On failure, -errno and only the kernel threads are |
147 | * thawed, so as to give a chance to the caller to do additional cleanups | |
148 | * (if any) before thawing the userspace tasks. So, it is the responsibility | |
149 | * of the caller to thaw the userspace tasks, when the time is right. | |
2aede851 RW |
150 | */ |
151 | int freeze_kernel_threads(void) | |
152 | { | |
153 | int error; | |
11b2ce2b | 154 | |
b842ee57 | 155 | printk("Freezing remaining freezable tasks ... "); |
a3201227 | 156 | pm_nosig_freezing = true; |
ebb12db5 | 157 | error = try_to_freeze_tasks(false); |
2aede851 RW |
158 | if (!error) |
159 | printk("done."); | |
7f33d49a | 160 | |
b842ee57 | 161 | printk("\n"); |
2aede851 | 162 | BUG_ON(in_atomic()); |
7f33d49a | 163 | |
03afed8b | 164 | if (error) |
379e0be8 | 165 | thaw_kernel_threads(); |
b842ee57 | 166 | return error; |
1da177e4 LT |
167 | } |
168 | ||
6cd8dedc | 169 | void thaw_processes(void) |
1da177e4 LT |
170 | { |
171 | struct task_struct *g, *p; | |
172 | ||
a3201227 TH |
173 | if (pm_freezing) |
174 | atomic_dec(&system_freezing_cnt); | |
175 | pm_freezing = false; | |
176 | pm_nosig_freezing = false; | |
177 | ||
6cd8dedc TH |
178 | oom_killer_enable(); |
179 | ||
180 | printk("Restarting tasks ... "); | |
181 | ||
182 | thaw_workqueues(); | |
183 | ||
1da177e4 | 184 | read_lock(&tasklist_lock); |
a9b6f562 | 185 | do_each_thread(g, p) { |
a5be2d0d | 186 | __thaw_task(p); |
a9b6f562 | 187 | } while_each_thread(g, p); |
1da177e4 | 188 | read_unlock(&tasklist_lock); |
7f33d49a | 189 | |
1da177e4 | 190 | schedule(); |
14b5b7cf | 191 | printk("done.\n"); |
1da177e4 LT |
192 | } |
193 | ||
181e9bde RW |
194 | void thaw_kernel_threads(void) |
195 | { | |
196 | struct task_struct *g, *p; | |
197 | ||
198 | pm_nosig_freezing = false; | |
199 | printk("Restarting kernel threads ... "); | |
200 | ||
201 | thaw_workqueues(); | |
202 | ||
203 | read_lock(&tasklist_lock); | |
204 | do_each_thread(g, p) { | |
205 | if (p->flags & (PF_KTHREAD | PF_WQ_WORKER)) | |
206 | __thaw_task(p); | |
207 | } while_each_thread(g, p); | |
208 | read_unlock(&tasklist_lock); | |
209 | ||
210 | schedule(); | |
211 | printk("done.\n"); | |
212 | } |