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