pm_trace displays the wrong time from the RTC
[deliverable/linux.git] / kernel / power / process.c
index 3434940a3df175679e4391f94755f09431c864c1..4da125ee533de0fecd5652b6518b2b8730d7dbf9 100644 (file)
@@ -75,21 +75,79 @@ void refrigerator(void)
        __set_current_state(save);
 }
 
-static void freeze_task(struct task_struct *p)
+static void fake_signal_wake_up(struct task_struct *p, int resume)
 {
        unsigned long flags;
 
-       if (!freezing(p)) {
+       spin_lock_irqsave(&p->sighand->siglock, flags);
+       signal_wake_up(p, resume);
+       spin_unlock_irqrestore(&p->sighand->siglock, flags);
+}
+
+static void send_fake_signal(struct task_struct *p)
+{
+       if (p->state == TASK_STOPPED)
+               force_sig_specific(SIGSTOP, p);
+       fake_signal_wake_up(p, p->state == TASK_STOPPED);
+}
+
+static int has_mm(struct task_struct *p)
+{
+       return (p->mm && !(p->flags & PF_BORROWED_MM));
+}
+
+/**
+ *     freeze_task - send a freeze request to given task
+ *     @p: task to send the request to
+ *     @with_mm_only: if set, the request will only be sent if the task has its
+ *             own mm
+ *     Return value: 0, if @with_mm_only is set and the task has no mm of its
+ *             own or the task is frozen, 1, otherwise
+ *
+ *     The freeze request is sent by seting the tasks's TIF_FREEZE flag and
+ *     either sending a fake signal to it or waking it up, depending on whether
+ *     or not it has its own mm (ie. it is a user land task).  If @with_mm_only
+ *     is set and the task has no mm of its own (ie. it is a kernel thread),
+ *     its TIF_FREEZE flag should not be set.
+ *
+ *     The task_lock() is necessary to prevent races with exit_mm() or
+ *     use_mm()/unuse_mm() from occuring.
+ */
+static int freeze_task(struct task_struct *p, int with_mm_only)
+{
+       int ret = 1;
+
+       task_lock(p);
+       if (freezing(p)) {
+               if (has_mm(p)) {
+                       if (!signal_pending(p))
+                               fake_signal_wake_up(p, 0);
+               } else {
+                       if (with_mm_only)
+                               ret = 0;
+                       else
+                               wake_up_state(p, TASK_INTERRUPTIBLE);
+               }
+       } else {
                rmb();
-               if (!frozen(p)) {
-                       set_freeze_flag(p);
-                       if (p->state == TASK_STOPPED)
-                               force_sig_specific(SIGSTOP, p);
-                       spin_lock_irqsave(&p->sighand->siglock, flags);
-                       signal_wake_up(p, p->state == TASK_STOPPED);
-                       spin_unlock_irqrestore(&p->sighand->siglock, flags);
+               if (frozen(p)) {
+                       ret = 0;
+               } else {
+                       if (has_mm(p)) {
+                               set_freeze_flag(p);
+                               send_fake_signal(p);
+                       } else {
+                               if (with_mm_only) {
+                                       ret = 0;
+                               } else {
+                                       set_freeze_flag(p);
+                                       wake_up_state(p, TASK_INTERRUPTIBLE);
+                               }
+                       }
                }
        }
+       task_unlock(p);
+       return ret;
 }
 
 static void cancel_freezing(struct task_struct *p)
@@ -119,31 +177,14 @@ static int try_to_freeze_tasks(int freeze_user_space)
                        if (frozen(p) || !freezeable(p))
                                continue;
 
-                       if (freeze_user_space) {
-                               if (p->state == TASK_TRACED &&
-                                   frozen(p->parent)) {
-                                       cancel_freezing(p);
-                                       continue;
-                               }
-                               /*
-                                * Kernel threads should not have TIF_FREEZE set
-                                * at this point, so we must ensure that either
-                                * p->mm is not NULL *and* PF_BORROWED_MM is
-                                * unset, or TIF_FRREZE is left unset.
-                                * The task_lock() is necessary to prevent races
-                                * with exit_mm() or use_mm()/unuse_mm() from
-                                * occuring.
-                                */
-                               task_lock(p);
-                               if (!p->mm || (p->flags & PF_BORROWED_MM)) {
-                                       task_unlock(p);
-                                       continue;
-                               }
-                               freeze_task(p);
-                               task_unlock(p);
-                       } else {
-                               freeze_task(p);
+                       if (p->state == TASK_TRACED && frozen(p->parent)) {
+                               cancel_freezing(p);
+                               continue;
                        }
+
+                       if (!freeze_task(p, freeze_user_space))
+                               continue;
+
                        if (!freezer_should_skip(p))
                                todo++;
                } while_each_thread(g, p);
@@ -191,7 +232,6 @@ int freeze_processes(void)
        if (error)
                return error;
 
-       sys_sync();
        error = try_to_freeze_tasks(FREEZER_KERNEL_THREADS);
        if (error)
                return error;
This page took 0.048837 seconds and 5 git commands to generate.