Merge git://git.infradead.org/mtd-2.6
[linux-2.6] / kernel / power / process.c
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
11 #include <linux/interrupt.h>
12 #include <linux/suspend.h>
13 #include <linux/module.h>
14 #include <linux/syscalls.h>
15 #include <linux/freezer.h>
16
17 /* 
18  * Timeout for stopping processes
19  */
20 #define TIMEOUT (20 * HZ)
21
22 static inline int freezeable(struct task_struct * p)
23 {
24         if ((p == current) ||
25             (p->flags & PF_NOFREEZE) ||
26             (p->exit_state != 0))
27                 return 0;
28         return 1;
29 }
30
31 static int try_to_freeze_tasks(bool sig_only)
32 {
33         struct task_struct *g, *p;
34         unsigned long end_time;
35         unsigned int todo;
36         struct timeval start, end;
37         u64 elapsed_csecs64;
38         unsigned int elapsed_csecs;
39
40         do_gettimeofday(&start);
41
42         end_time = jiffies + TIMEOUT;
43         do {
44                 todo = 0;
45                 read_lock(&tasklist_lock);
46                 do_each_thread(g, p) {
47                         if (frozen(p) || !freezeable(p))
48                                 continue;
49
50                         if (!freeze_task(p, sig_only))
51                                 continue;
52
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))
61                                 todo++;
62                 } while_each_thread(g, p);
63                 read_unlock(&tasklist_lock);
64                 yield();                        /* Yield is okay here */
65                 if (time_after(jiffies, end_time))
66                         break;
67         } while (todo);
68
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
74         if (todo) {
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                  */
80                 printk("\n");
81                 printk(KERN_ERR "Freezing of tasks failed after %d.%02d seconds "
82                                 "(%d tasks refusing to freeze):\n",
83                                 elapsed_csecs / 100, elapsed_csecs % 100, todo);
84                 show_state();
85                 read_lock(&tasklist_lock);
86                 do_each_thread(g, p) {
87                         task_lock(p);
88                         if (freezing(p) && !freezer_should_skip(p))
89                                 printk(KERN_ERR " %s\n", p->comm);
90                         cancel_freezing(p);
91                         task_unlock(p);
92                 } while_each_thread(g, p);
93                 read_unlock(&tasklist_lock);
94         } else {
95                 printk("(elapsed %d.%02d seconds) ", elapsed_csecs / 100,
96                         elapsed_csecs % 100);
97         }
98
99         return todo ? -EBUSY : 0;
100 }
101
102 /**
103  *      freeze_processes - tell processes to enter the refrigerator
104  */
105 int freeze_processes(void)
106 {
107         int error;
108
109         printk("Freezing user space processes ... ");
110         error = try_to_freeze_tasks(true);
111         if (error)
112                 goto Exit;
113         printk("done.\n");
114
115         printk("Freezing remaining freezable tasks ... ");
116         error = try_to_freeze_tasks(false);
117         if (error)
118                 goto Exit;
119         printk("done.");
120  Exit:
121         BUG_ON(in_atomic());
122         printk("\n");
123         return error;
124 }
125
126 static void thaw_tasks(bool nosig_only)
127 {
128         struct task_struct *g, *p;
129
130         read_lock(&tasklist_lock);
131         do_each_thread(g, p) {
132                 if (!freezeable(p))
133                         continue;
134
135                 if (nosig_only && should_send_signal(p))
136                         continue;
137
138                 if (cgroup_frozen(p))
139                         continue;
140
141                 thaw_process(p);
142         } while_each_thread(g, p);
143         read_unlock(&tasklist_lock);
144 }
145
146 void thaw_processes(void)
147 {
148         printk("Restarting tasks ... ");
149         thaw_tasks(true);
150         thaw_tasks(false);
151         schedule();
152         printk("done.\n");
153 }
154