X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=kernel%2Fpower%2Fprocess.c;h=5ade1bdcf366a9e93789097ea99ba8aba9dceccc;hb=cd18964a1d67c4989474ffca0109ef1c0f8502a3;hp=02a1b3a9fa908e91659659de454c72b88d4dfb50;hpb=543cc27d09643640cbc34189c03a40beb8227aef;p=safe%2Fjmp%2Flinux-2.6 diff --git a/kernel/power/process.c b/kernel/power/process.c index 02a1b3a..5ade1bd 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -8,127 +8,159 @@ #undef DEBUG -#include #include +#include #include #include +#include +#include +#include /* * Timeout for stopping processes */ -#define TIMEOUT (6 * HZ) - +#define TIMEOUT (20 * HZ) static inline int freezeable(struct task_struct * p) { - if ((p == current) || + if ((p == current) || (p->flags & PF_NOFREEZE) || - (p->exit_state == EXIT_ZOMBIE) || - (p->exit_state == EXIT_DEAD) || - (p->state == TASK_STOPPED) || - (p->state == TASK_TRACED)) + (p->exit_state != 0)) return 0; return 1; } -/* Refrigerator is place where frozen processes are stored :-). */ -void refrigerator(void) -{ - /* Hmm, should we be allowed to suspend when there are realtime - processes around? */ - long save; - save = current->state; - pr_debug("%s entered refrigerator\n", current->comm); - printk("="); - - frozen_process(current); - spin_lock_irq(¤t->sighand->siglock); - recalc_sigpending(); /* We sent fake signal, clean it up */ - spin_unlock_irq(¤t->sighand->siglock); - - while (frozen(current)) { - current->state = TASK_UNINTERRUPTIBLE; - schedule(); - } - pr_debug("%s left refrigerator\n", current->comm); - current->state = save; -} - -/* 0 = success, else # of processes that we failed to stop */ -int freeze_processes(void) +static int try_to_freeze_tasks(bool sig_only) { - int todo; - unsigned long start_time; struct task_struct *g, *p; - unsigned long flags; + unsigned long end_time; + unsigned int todo; + struct timeval start, end; + u64 elapsed_csecs64; + unsigned int elapsed_csecs; - printk( "Stopping tasks: " ); - start_time = jiffies; - do { + do_gettimeofday(&start); + + end_time = jiffies + TIMEOUT; + while (true) { todo = 0; read_lock(&tasklist_lock); do_each_thread(g, p) { - if (!freezeable(p)) + if (frozen(p) || !freezeable(p)) continue; - if (frozen(p)) + + if (!freeze_task(p, sig_only)) continue; - freeze(p); - spin_lock_irqsave(&p->sighand->siglock, flags); - signal_wake_up(p, 0); - spin_unlock_irqrestore(&p->sighand->siglock, flags); - todo++; + /* + * Now that we've done set_freeze_flag, don't + * perturb a task in TASK_STOPPED or TASK_TRACED. + * It is "frozen enough". If the task does wake + * up, it will immediately call try_to_freeze. + */ + if (!task_is_stopped_or_traced(p) && + !freezer_should_skip(p)) + todo++; } while_each_thread(g, p); read_unlock(&tasklist_lock); - yield(); /* Yield is okay here */ - if (todo && time_after(jiffies, start_time + TIMEOUT)) { - printk( "\n" ); - printk(KERN_ERR " stopping tasks timed out (%d tasks remaining)\n", todo ); + if (!todo || time_after(jiffies, end_time)) break; - } - } while(todo); - - /* This does not unfreeze processes that are already frozen - * (we have slightly ugly calling convention in that respect, - * and caller must call thaw_processes() if something fails), - * but it cleans up leftover PF_FREEZE requests. - */ + + /* + * We need to retry, but first give the freezing tasks some + * time to enter the regrigerator. + */ + msleep(10); + } + + do_gettimeofday(&end); + elapsed_csecs64 = timeval_to_ns(&end) - timeval_to_ns(&start); + do_div(elapsed_csecs64, NSEC_PER_SEC / 100); + elapsed_csecs = elapsed_csecs64; + if (todo) { + /* This does not unfreeze processes that are already frozen + * (we have slightly ugly calling convention in that respect, + * and caller must call thaw_processes() if something fails), + * but it cleans up leftover PF_FREEZE requests. + */ + printk("\n"); + printk(KERN_ERR "Freezing of tasks failed after %d.%02d seconds " + "(%d tasks refusing to freeze):\n", + elapsed_csecs / 100, elapsed_csecs % 100, todo); + show_state(); read_lock(&tasklist_lock); - do_each_thread(g, p) - if (freezing(p)) { - pr_debug(" clean up: %s\n", p->comm); - p->flags &= ~PF_FREEZE; - spin_lock_irqsave(&p->sighand->siglock, flags); - recalc_sigpending_tsk(p); - spin_unlock_irqrestore(&p->sighand->siglock, flags); - } - while_each_thread(g, p); + do_each_thread(g, p) { + task_lock(p); + if (freezing(p) && !freezer_should_skip(p)) + printk(KERN_ERR " %s\n", p->comm); + cancel_freezing(p); + task_unlock(p); + } while_each_thread(g, p); read_unlock(&tasklist_lock); - return todo; + } else { + printk("(elapsed %d.%02d seconds) ", elapsed_csecs / 100, + elapsed_csecs % 100); } - printk( "|\n" ); + return todo ? -EBUSY : 0; +} + +/** + * freeze_processes - tell processes to enter the refrigerator + */ +int freeze_processes(void) +{ + int error; + + printk("Freezing user space processes ... "); + error = try_to_freeze_tasks(true); + if (error) + goto Exit; + printk("done.\n"); + + printk("Freezing remaining freezable tasks ... "); + error = try_to_freeze_tasks(false); + if (error) + goto Exit; + printk("done."); + + oom_killer_disable(); + Exit: BUG_ON(in_atomic()); - return 0; + printk("\n"); + + return error; } -void thaw_processes(void) +static void thaw_tasks(bool nosig_only) { struct task_struct *g, *p; - printk( "Restarting tasks..." ); read_lock(&tasklist_lock); do_each_thread(g, p) { if (!freezeable(p)) continue; - if (!thaw_process(p)) - printk(KERN_INFO " Strange, %s not stopped\n", p->comm ); - } while_each_thread(g, p); + if (nosig_only && should_send_signal(p)) + continue; + + if (cgroup_frozen(p)) + continue; + + thaw_process(p); + } while_each_thread(g, p); read_unlock(&tasklist_lock); +} + +void thaw_processes(void) +{ + oom_killer_enable(); + + printk("Restarting tasks ... "); + thaw_tasks(true); + thaw_tasks(false); schedule(); - printk( " done\n" ); + printk("done.\n"); } -EXPORT_SYMBOL(refrigerator);