PM: Allow wakeup events to abort freezing of tasks
Rafael J. Wysocki [Mon, 4 Oct 2010 20:07:32 +0000 (22:07 +0200)]
If there is a wakeup event during the freezing of tasks, suspend or
hibernation will fail anyway.  Since try_to_freeze_tasks() can take
up to 20 seconds to complete or fail, aborting it as soon as a wakeup
event is detected improves the worst case wakeup latency.

Based on a patch from Arve Hjønnevåg.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Pavel Machek <pavel@ucw.cz>

include/linux/suspend.h
kernel/power/process.c

index 6b1712c..2669751 100644 (file)
@@ -308,6 +308,8 @@ static inline int unregister_pm_notifier(struct notifier_block *nb)
 }
 
 #define pm_notifier(fn, pri)   do { (void)(fn); } while (0)
+
+static inline bool pm_check_wakeup_events(void) { return true; }
 #endif /* !CONFIG_PM_SLEEP */
 
 extern struct mutex pm_mutex;
index 028a995..e50b4c1 100644 (file)
@@ -40,6 +40,7 @@ static int try_to_freeze_tasks(bool sig_only)
        struct timeval start, end;
        u64 elapsed_csecs64;
        unsigned int elapsed_csecs;
+       bool wakeup = false;
 
        do_gettimeofday(&start);
 
@@ -78,6 +79,11 @@ static int try_to_freeze_tasks(bool sig_only)
                if (!todo || time_after(jiffies, end_time))
                        break;
 
+               if (!pm_check_wakeup_events()) {
+                       wakeup = true;
+                       break;
+               }
+
                /*
                 * We need to retry, but first give the freezing tasks some
                 * time to enter the regrigerator.
@@ -97,8 +103,9 @@ static int try_to_freeze_tasks(bool sig_only)
                 * but it cleans up leftover PF_FREEZE requests.
                 */
                printk("\n");
-               printk(KERN_ERR "Freezing of tasks failed after %d.%02d seconds "
+               printk(KERN_ERR "Freezing of tasks %s after %d.%02d seconds "
                       "(%d tasks refusing to freeze, wq_busy=%d):\n",
+                      wakeup ? "aborted" : "failed",
                       elapsed_csecs / 100, elapsed_csecs % 100,
                       todo - wq_busy, wq_busy);
 
@@ -107,7 +114,7 @@ static int try_to_freeze_tasks(bool sig_only)
                read_lock(&tasklist_lock);
                do_each_thread(g, p) {
                        task_lock(p);
-                       if (freezing(p) && !freezer_should_skip(p))
+                       if (!wakeup && freezing(p) && !freezer_should_skip(p))
                                sched_show_task(p);
                        cancel_freezing(p);
                        task_unlock(p);