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