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