]>
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 | |
1da177e4 LT |
25 | static inline int freezeable(struct task_struct * p) |
26 | { | |
1065d130 | 27 | if ((p == current) || |
1da177e4 | 28 | (p->flags & PF_NOFREEZE) || |
1065d130 | 29 | (p->exit_state != 0)) |
1da177e4 LT |
30 | return 0; |
31 | return 1; | |
32 | } | |
33 | ||
ebb12db5 | 34 | static int try_to_freeze_tasks(bool sig_only) |
1da177e4 | 35 | { |
1da177e4 | 36 | struct task_struct *g, *p; |
11b2ce2b RW |
37 | unsigned long end_time; |
38 | unsigned int todo; | |
a0a1a5fd | 39 | bool wq_busy = false; |
438e2ce6 | 40 | struct timeval start, end; |
f0af566d | 41 | u64 elapsed_csecs64; |
438e2ce6 | 42 | unsigned int elapsed_csecs; |
dbeeec5f | 43 | bool wakeup = false; |
438e2ce6 RW |
44 | |
45 | do_gettimeofday(&start); | |
3e1d1d28 | 46 | |
11b2ce2b | 47 | end_time = jiffies + TIMEOUT; |
a0a1a5fd TH |
48 | |
49 | if (!sig_only) | |
50 | freeze_workqueues_begin(); | |
51 | ||
be404f02 | 52 | while (true) { |
11b2ce2b | 53 | todo = 0; |
1da177e4 LT |
54 | read_lock(&tasklist_lock); |
55 | do_each_thread(g, p) { | |
0c1eecfb | 56 | if (frozen(p) || !freezeable(p)) |
1da177e4 | 57 | continue; |
11b2ce2b | 58 | |
ebb12db5 | 59 | if (!freeze_task(p, sig_only)) |
d5d8c597 RW |
60 | continue; |
61 | ||
13b1c3d4 RM |
62 | /* |
63 | * Now that we've done set_freeze_flag, don't | |
64 | * perturb a task in TASK_STOPPED or TASK_TRACED. | |
65 | * It is "frozen enough". If the task does wake | |
66 | * up, it will immediately call try_to_freeze. | |
8cfe400c TH |
67 | * |
68 | * Because freeze_task() goes through p's | |
69 | * scheduler lock after setting TIF_FREEZE, it's | |
70 | * guaranteed that either we see TASK_RUNNING or | |
71 | * try_to_stop() after schedule() in ptrace/signal | |
72 | * stop sees TIF_FREEZE. | |
13b1c3d4 RM |
73 | */ |
74 | if (!task_is_stopped_or_traced(p) && | |
75 | !freezer_should_skip(p)) | |
ba96a0c8 | 76 | todo++; |
1da177e4 LT |
77 | } while_each_thread(g, p); |
78 | read_unlock(&tasklist_lock); | |
a0a1a5fd TH |
79 | |
80 | if (!sig_only) { | |
81 | wq_busy = freeze_workqueues_busy(); | |
82 | todo += wq_busy; | |
83 | } | |
84 | ||
be404f02 | 85 | if (!todo || time_after(jiffies, end_time)) |
6161b2ce | 86 | break; |
be404f02 | 87 | |
dbeeec5f RW |
88 | if (!pm_check_wakeup_events()) { |
89 | wakeup = true; | |
90 | break; | |
91 | } | |
92 | ||
be404f02 TH |
93 | /* |
94 | * We need to retry, but first give the freezing tasks some | |
95 | * time to enter the regrigerator. | |
96 | */ | |
97 | msleep(10); | |
98 | } | |
3e1d1d28 | 99 | |
438e2ce6 RW |
100 | do_gettimeofday(&end); |
101 | elapsed_csecs64 = timeval_to_ns(&end) - timeval_to_ns(&start); | |
102 | do_div(elapsed_csecs64, NSEC_PER_SEC / 100); | |
103 | elapsed_csecs = elapsed_csecs64; | |
104 | ||
6161b2ce | 105 | if (todo) { |
11b2ce2b RW |
106 | /* This does not unfreeze processes that are already frozen |
107 | * (we have slightly ugly calling convention in that respect, | |
108 | * and caller must call thaw_processes() if something fails), | |
109 | * but it cleans up leftover PF_FREEZE requests. | |
110 | */ | |
14b5b7cf | 111 | printk("\n"); |
dbeeec5f | 112 | printk(KERN_ERR "Freezing of tasks %s after %d.%02d seconds " |
a0a1a5fd | 113 | "(%d tasks refusing to freeze, wq_busy=%d):\n", |
dbeeec5f | 114 | wakeup ? "aborted" : "failed", |
a0a1a5fd TH |
115 | elapsed_csecs / 100, elapsed_csecs % 100, |
116 | todo - wq_busy, wq_busy); | |
117 | ||
118 | thaw_workqueues(); | |
119 | ||
6161b2ce | 120 | read_lock(&tasklist_lock); |
02aaeb9b | 121 | do_each_thread(g, p) { |
33e1c288 | 122 | task_lock(p); |
dbeeec5f | 123 | if (!wakeup && freezing(p) && !freezer_should_skip(p)) |
4f598458 | 124 | sched_show_task(p); |
a7ef7878 | 125 | cancel_freezing(p); |
33e1c288 | 126 | task_unlock(p); |
02aaeb9b | 127 | } while_each_thread(g, p); |
6161b2ce | 128 | read_unlock(&tasklist_lock); |
438e2ce6 RW |
129 | } else { |
130 | printk("(elapsed %d.%02d seconds) ", elapsed_csecs / 100, | |
131 | elapsed_csecs % 100); | |
6161b2ce PM |
132 | } |
133 | ||
e7cd8a72 | 134 | return todo ? -EBUSY : 0; |
11b2ce2b RW |
135 | } |
136 | ||
137 | /** | |
138 | * freeze_processes - tell processes to enter the refrigerator | |
11b2ce2b RW |
139 | */ |
140 | int freeze_processes(void) | |
141 | { | |
e7cd8a72 | 142 | int error; |
11b2ce2b | 143 | |
b842ee57 | 144 | printk("Freezing user space processes ... "); |
ebb12db5 | 145 | error = try_to_freeze_tasks(true); |
e7cd8a72 | 146 | if (error) |
b842ee57 RW |
147 | goto Exit; |
148 | printk("done.\n"); | |
11b2ce2b | 149 | |
b842ee57 | 150 | printk("Freezing remaining freezable tasks ... "); |
ebb12db5 | 151 | error = try_to_freeze_tasks(false); |
e7cd8a72 | 152 | if (error) |
b842ee57 RW |
153 | goto Exit; |
154 | printk("done."); | |
7f33d49a RW |
155 | |
156 | oom_killer_disable(); | |
b842ee57 | 157 | Exit: |
1da177e4 | 158 | BUG_ON(in_atomic()); |
b842ee57 | 159 | printk("\n"); |
7f33d49a | 160 | |
b842ee57 | 161 | return error; |
1da177e4 LT |
162 | } |
163 | ||
ebb12db5 | 164 | static void thaw_tasks(bool nosig_only) |
1da177e4 LT |
165 | { |
166 | struct task_struct *g, *p; | |
167 | ||
1da177e4 | 168 | read_lock(&tasklist_lock); |
a9b6f562 RW |
169 | do_each_thread(g, p) { |
170 | if (!freezeable(p)) | |
171 | continue; | |
ff39593a | 172 | |
ebb12db5 | 173 | if (nosig_only && should_send_signal(p)) |
a9b6f562 | 174 | continue; |
1da177e4 | 175 | |
5a7aadfe | 176 | if (cgroup_freezing_or_frozen(p)) |
5a06915c MH |
177 | continue; |
178 | ||
ba96a0c8 | 179 | thaw_process(p); |
a9b6f562 | 180 | } while_each_thread(g, p); |
1da177e4 | 181 | read_unlock(&tasklist_lock); |
a9b6f562 RW |
182 | } |
183 | ||
184 | void thaw_processes(void) | |
185 | { | |
7f33d49a RW |
186 | oom_killer_enable(); |
187 | ||
a9b6f562 | 188 | printk("Restarting tasks ... "); |
a0a1a5fd | 189 | thaw_workqueues(); |
ebb12db5 RW |
190 | thaw_tasks(true); |
191 | thaw_tasks(false); | |
1da177e4 | 192 | schedule(); |
14b5b7cf | 193 | printk("done.\n"); |
1da177e4 LT |
194 | } |
195 |