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