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