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 98088e0e71e..06ec8869dbf 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -30,9 +30,10 @@ static int try_to_freeze_tasks(bool user_only)  	unsigned int todo;  	bool wq_busy = false;  	struct timeval start, end; -	u64 elapsed_csecs64; -	unsigned int elapsed_csecs; +	u64 elapsed_msecs64; +	unsigned int elapsed_msecs;  	bool wakeup = false; +	int sleep_usecs = USEC_PER_MSEC;  	do_gettimeofday(&start); @@ -68,22 +69,25 @@ static int try_to_freeze_tasks(bool user_only)  		/*  		 * We need to retry, but first give the freezing tasks some -		 * time to enter the refrigerator. +		 * time to enter the refrigerator.  Start with an initial +		 * 1 ms sleep followed by exponential backoff until 8 ms.  		 */ -		msleep(10); +		usleep_range(sleep_usecs / 2, sleep_usecs); +		if (sleep_usecs < 8 * USEC_PER_MSEC) +			sleep_usecs *= 2;  	}  	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; +	elapsed_msecs64 = timeval_to_ns(&end) - timeval_to_ns(&start); +	do_div(elapsed_msecs64, NSEC_PER_MSEC); +	elapsed_msecs = elapsed_msecs64;  	if (todo) {  		printk("\n"); -		printk(KERN_ERR "Freezing of tasks %s after %d.%02d seconds " +		printk(KERN_ERR "Freezing of tasks %s after %d.%03d seconds "  		       "(%d tasks refusing to freeze, wq_busy=%d):\n",  		       wakeup ? "aborted" : "failed", -		       elapsed_csecs / 100, elapsed_csecs % 100, +		       elapsed_msecs / 1000, elapsed_msecs % 1000,  		       todo - wq_busy, wq_busy);  		if (!wakeup) { @@ -96,8 +100,8 @@ static int try_to_freeze_tasks(bool user_only)  			read_unlock(&tasklist_lock);  		}  	} else { -		printk("(elapsed %d.%02d seconds) ", elapsed_csecs / 100, -			elapsed_csecs % 100); +		printk("(elapsed %d.%03d seconds) ", elapsed_msecs / 1000, +			elapsed_msecs % 1000);  	}  	return todo ? -EBUSY : 0; @@ -105,6 +109,8 @@ static int try_to_freeze_tasks(bool user_only)  /**   * freeze_processes - Signal user space processes to enter the refrigerator. + * The current thread will not be frozen.  The same process that calls + * freeze_processes must later call thaw_processes.   *   * On success, returns 0.  On failure, -errno and system is fully thawed.   */ @@ -116,6 +122,9 @@ int freeze_processes(void)  	if (error)  		return error; +	/* Make sure this task doesn't get frozen */ +	current->flags |= PF_SUSPEND_TASK; +  	if (!pm_freezing)  		atomic_inc(&system_freezing_cnt); @@ -164,6 +173,7 @@ int freeze_kernel_threads(void)  void thaw_processes(void)  {  	struct task_struct *g, *p; +	struct task_struct *curr = current;  	if (pm_freezing)  		atomic_dec(&system_freezing_cnt); @@ -178,10 +188,15 @@ void thaw_processes(void)  	read_lock(&tasklist_lock);  	do_each_thread(g, p) { +		/* No other threads should have PF_SUSPEND_TASK set */ +		WARN_ON((p != curr) && (p->flags & PF_SUSPEND_TASK));  		__thaw_task(p);  	} while_each_thread(g, p);  	read_unlock(&tasklist_lock); +	WARN_ON(!(curr->flags & PF_SUSPEND_TASK)); +	curr->flags &= ~PF_SUSPEND_TASK; +  	usermodehelper_enable();  	schedule(); | 
