diff options
Diffstat (limited to 'kernel/power/process.c')
| -rw-r--r-- | kernel/power/process.c | 37 |
1 files changed, 26 insertions, 11 deletions
diff --git a/kernel/power/process.c b/kernel/power/process.c index 98088e0e71e8..06ec8869dbf1 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c | |||
| @@ -30,9 +30,10 @@ static int try_to_freeze_tasks(bool user_only) | |||
| 30 | unsigned int todo; | 30 | unsigned int todo; |
| 31 | bool wq_busy = false; | 31 | bool wq_busy = false; |
| 32 | struct timeval start, end; | 32 | struct timeval start, end; |
| 33 | u64 elapsed_csecs64; | 33 | u64 elapsed_msecs64; |
| 34 | unsigned int elapsed_csecs; | 34 | unsigned int elapsed_msecs; |
| 35 | bool wakeup = false; | 35 | bool wakeup = false; |
| 36 | int sleep_usecs = USEC_PER_MSEC; | ||
| 36 | 37 | ||
| 37 | do_gettimeofday(&start); | 38 | do_gettimeofday(&start); |
| 38 | 39 | ||
| @@ -68,22 +69,25 @@ static int try_to_freeze_tasks(bool user_only) | |||
| 68 | 69 | ||
| 69 | /* | 70 | /* |
| 70 | * We need to retry, but first give the freezing tasks some | 71 | * We need to retry, but first give the freezing tasks some |
| 71 | * time to enter the refrigerator. | 72 | * time to enter the refrigerator. Start with an initial |
| 73 | * 1 ms sleep followed by exponential backoff until 8 ms. | ||
| 72 | */ | 74 | */ |
| 73 | msleep(10); | 75 | usleep_range(sleep_usecs / 2, sleep_usecs); |
| 76 | if (sleep_usecs < 8 * USEC_PER_MSEC) | ||
| 77 | sleep_usecs *= 2; | ||
| 74 | } | 78 | } |
| 75 | 79 | ||
| 76 | do_gettimeofday(&end); | 80 | do_gettimeofday(&end); |
| 77 | elapsed_csecs64 = timeval_to_ns(&end) - timeval_to_ns(&start); | 81 | elapsed_msecs64 = timeval_to_ns(&end) - timeval_to_ns(&start); |
| 78 | do_div(elapsed_csecs64, NSEC_PER_SEC / 100); | 82 | do_div(elapsed_msecs64, NSEC_PER_MSEC); |
| 79 | elapsed_csecs = elapsed_csecs64; | 83 | elapsed_msecs = elapsed_msecs64; |
| 80 | 84 | ||
| 81 | if (todo) { | 85 | if (todo) { |
| 82 | printk("\n"); | 86 | printk("\n"); |
| 83 | printk(KERN_ERR "Freezing of tasks %s after %d.%02d seconds " | 87 | printk(KERN_ERR "Freezing of tasks %s after %d.%03d seconds " |
| 84 | "(%d tasks refusing to freeze, wq_busy=%d):\n", | 88 | "(%d tasks refusing to freeze, wq_busy=%d):\n", |
| 85 | wakeup ? "aborted" : "failed", | 89 | wakeup ? "aborted" : "failed", |
| 86 | elapsed_csecs / 100, elapsed_csecs % 100, | 90 | elapsed_msecs / 1000, elapsed_msecs % 1000, |
| 87 | todo - wq_busy, wq_busy); | 91 | todo - wq_busy, wq_busy); |
| 88 | 92 | ||
| 89 | if (!wakeup) { | 93 | if (!wakeup) { |
| @@ -96,8 +100,8 @@ static int try_to_freeze_tasks(bool user_only) | |||
| 96 | read_unlock(&tasklist_lock); | 100 | read_unlock(&tasklist_lock); |
| 97 | } | 101 | } |
| 98 | } else { | 102 | } else { |
| 99 | printk("(elapsed %d.%02d seconds) ", elapsed_csecs / 100, | 103 | printk("(elapsed %d.%03d seconds) ", elapsed_msecs / 1000, |
| 100 | elapsed_csecs % 100); | 104 | elapsed_msecs % 1000); |
| 101 | } | 105 | } |
| 102 | 106 | ||
| 103 | return todo ? -EBUSY : 0; | 107 | return todo ? -EBUSY : 0; |
| @@ -105,6 +109,8 @@ static int try_to_freeze_tasks(bool user_only) | |||
| 105 | 109 | ||
| 106 | /** | 110 | /** |
| 107 | * freeze_processes - Signal user space processes to enter the refrigerator. | 111 | * freeze_processes - Signal user space processes to enter the refrigerator. |
| 112 | * The current thread will not be frozen. The same process that calls | ||
| 113 | * freeze_processes must later call thaw_processes. | ||
| 108 | * | 114 | * |
| 109 | * On success, returns 0. On failure, -errno and system is fully thawed. | 115 | * On success, returns 0. On failure, -errno and system is fully thawed. |
| 110 | */ | 116 | */ |
| @@ -116,6 +122,9 @@ int freeze_processes(void) | |||
| 116 | if (error) | 122 | if (error) |
| 117 | return error; | 123 | return error; |
| 118 | 124 | ||
| 125 | /* Make sure this task doesn't get frozen */ | ||
| 126 | current->flags |= PF_SUSPEND_TASK; | ||
| 127 | |||
| 119 | if (!pm_freezing) | 128 | if (!pm_freezing) |
| 120 | atomic_inc(&system_freezing_cnt); | 129 | atomic_inc(&system_freezing_cnt); |
| 121 | 130 | ||
| @@ -164,6 +173,7 @@ int freeze_kernel_threads(void) | |||
| 164 | void thaw_processes(void) | 173 | void thaw_processes(void) |
| 165 | { | 174 | { |
| 166 | struct task_struct *g, *p; | 175 | struct task_struct *g, *p; |
| 176 | struct task_struct *curr = current; | ||
| 167 | 177 | ||
| 168 | if (pm_freezing) | 178 | if (pm_freezing) |
| 169 | atomic_dec(&system_freezing_cnt); | 179 | atomic_dec(&system_freezing_cnt); |
| @@ -178,10 +188,15 @@ void thaw_processes(void) | |||
| 178 | 188 | ||
| 179 | read_lock(&tasklist_lock); | 189 | read_lock(&tasklist_lock); |
| 180 | do_each_thread(g, p) { | 190 | do_each_thread(g, p) { |
| 191 | /* No other threads should have PF_SUSPEND_TASK set */ | ||
| 192 | WARN_ON((p != curr) && (p->flags & PF_SUSPEND_TASK)); | ||
| 181 | __thaw_task(p); | 193 | __thaw_task(p); |
| 182 | } while_each_thread(g, p); | 194 | } while_each_thread(g, p); |
| 183 | read_unlock(&tasklist_lock); | 195 | read_unlock(&tasklist_lock); |
| 184 | 196 | ||
| 197 | WARN_ON(!(curr->flags & PF_SUSPEND_TASK)); | ||
| 198 | curr->flags &= ~PF_SUSPEND_TASK; | ||
| 199 | |||
| 185 | usermodehelper_enable(); | 200 | usermodehelper_enable(); |
| 186 | 201 | ||
| 187 | schedule(); | 202 | schedule(); |
