| /* | 
 |  * drivers/power/process.c - Functions for starting/stopping processes on  | 
 |  *                           suspend transitions. | 
 |  * | 
 |  * Originally from swsusp. | 
 |  */ | 
 |  | 
 |  | 
 | #undef DEBUG | 
 |  | 
 | #include <linux/interrupt.h> | 
 | #include <linux/suspend.h> | 
 | #include <linux/module.h> | 
 | #include <linux/syscalls.h> | 
 | #include <linux/freezer.h> | 
 |  | 
 | /*  | 
 |  * Timeout for stopping processes | 
 |  */ | 
 | #define TIMEOUT	(20 * HZ) | 
 |  | 
 | static inline int freezeable(struct task_struct * p) | 
 | { | 
 | 	if ((p == current) || | 
 | 	    (p->flags & PF_NOFREEZE) || | 
 | 	    (p->exit_state != 0)) | 
 | 		return 0; | 
 | 	return 1; | 
 | } | 
 |  | 
 | /* | 
 |  * freezing is complete, mark current process as frozen | 
 |  */ | 
 | static inline void frozen_process(void) | 
 | { | 
 | 	if (!unlikely(current->flags & PF_NOFREEZE)) { | 
 | 		current->flags |= PF_FROZEN; | 
 | 		wmb(); | 
 | 	} | 
 | 	clear_freeze_flag(current); | 
 | } | 
 |  | 
 | /* 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; | 
 |  | 
 | 	task_lock(current); | 
 | 	if (freezing(current)) { | 
 | 		frozen_process(); | 
 | 		task_unlock(current); | 
 | 	} else { | 
 | 		task_unlock(current); | 
 | 		return; | 
 | 	} | 
 | 	save = current->state; | 
 | 	pr_debug("%s entered refrigerator\n", current->comm); | 
 |  | 
 | 	spin_lock_irq(¤t->sighand->siglock); | 
 | 	recalc_sigpending(); /* We sent fake signal, clean it up */ | 
 | 	spin_unlock_irq(¤t->sighand->siglock); | 
 |  | 
 | 	for (;;) { | 
 | 		set_current_state(TASK_UNINTERRUPTIBLE); | 
 | 		if (!frozen(current)) | 
 | 			break; | 
 | 		schedule(); | 
 | 	} | 
 | 	pr_debug("%s left refrigerator\n", current->comm); | 
 | 	__set_current_state(save); | 
 | } | 
 |  | 
 | static void fake_signal_wake_up(struct task_struct *p) | 
 | { | 
 | 	unsigned long flags; | 
 |  | 
 | 	spin_lock_irqsave(&p->sighand->siglock, flags); | 
 | 	signal_wake_up(p, 0); | 
 | 	spin_unlock_irqrestore(&p->sighand->siglock, flags); | 
 | } | 
 |  | 
 | static inline bool should_send_signal(struct task_struct *p) | 
 | { | 
 | 	return !(p->flags & PF_FREEZER_NOSIG); | 
 | } | 
 |  | 
 | /** | 
 |  *	freeze_task - send a freeze request to given task | 
 |  *	@p: task to send the request to | 
 |  *	@sig_only: if set, the request will only be sent if the task has the | 
 |  *		PF_FREEZER_NOSIG flag unset | 
 |  *	Return value: 'false', if @sig_only is set and the task has | 
 |  *		PF_FREEZER_NOSIG set or the task is frozen, 'true', otherwise | 
 |  * | 
 |  *	The freeze request is sent by setting 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 PF_FREEZER_NOSIG set.  If @sig_only is set and the task | 
 |  *	has PF_FREEZER_NOSIG set (ie. it is a typical kernel thread), its | 
 |  *	TIF_FREEZE flag will not be set. | 
 |  */ | 
 | static bool freeze_task(struct task_struct *p, bool sig_only) | 
 | { | 
 | 	/* | 
 | 	 * We first check if the task is freezing and next if it has already | 
 | 	 * been frozen to avoid the race with frozen_process() which first marks | 
 | 	 * the task as frozen and next clears its TIF_FREEZE. | 
 | 	 */ | 
 | 	if (!freezing(p)) { | 
 | 		rmb(); | 
 | 		if (frozen(p)) | 
 | 			return false; | 
 |  | 
 | 		if (!sig_only || should_send_signal(p)) | 
 | 			set_freeze_flag(p); | 
 | 		else | 
 | 			return false; | 
 | 	} | 
 |  | 
 | 	if (should_send_signal(p)) { | 
 | 		if (!signal_pending(p)) | 
 | 			fake_signal_wake_up(p); | 
 | 	} else if (sig_only) { | 
 | 		return false; | 
 | 	} else { | 
 | 		wake_up_state(p, TASK_INTERRUPTIBLE); | 
 | 	} | 
 |  | 
 | 	return true; | 
 | } | 
 |  | 
 | static void cancel_freezing(struct task_struct *p) | 
 | { | 
 | 	unsigned long flags; | 
 |  | 
 | 	if (freezing(p)) { | 
 | 		pr_debug("  clean up: %s\n", p->comm); | 
 | 		clear_freeze_flag(p); | 
 | 		spin_lock_irqsave(&p->sighand->siglock, flags); | 
 | 		recalc_sigpending_and_wake(p); | 
 | 		spin_unlock_irqrestore(&p->sighand->siglock, flags); | 
 | 	} | 
 | } | 
 |  | 
 | static int try_to_freeze_tasks(bool sig_only) | 
 | { | 
 | 	struct task_struct *g, *p; | 
 | 	unsigned long end_time; | 
 | 	unsigned int todo; | 
 | 	struct timeval start, end; | 
 | 	s64 elapsed_csecs64; | 
 | 	unsigned int elapsed_csecs; | 
 |  | 
 | 	do_gettimeofday(&start); | 
 |  | 
 | 	end_time = jiffies + TIMEOUT; | 
 | 	do { | 
 | 		todo = 0; | 
 | 		read_lock(&tasklist_lock); | 
 | 		do_each_thread(g, p) { | 
 | 			if (frozen(p) || !freezeable(p)) | 
 | 				continue; | 
 |  | 
 | 			if (!freeze_task(p, sig_only)) | 
 | 				continue; | 
 |  | 
 | 			/* | 
 | 			 * 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 (time_after(jiffies, end_time)) | 
 | 			break; | 
 | 	} while (todo); | 
 |  | 
 | 	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) { | 
 | 			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); | 
 | 	} else { | 
 | 		printk("(elapsed %d.%02d seconds) ", elapsed_csecs / 100, | 
 | 			elapsed_csecs % 100); | 
 | 	} | 
 |  | 
 | 	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."); | 
 |  Exit: | 
 | 	BUG_ON(in_atomic()); | 
 | 	printk("\n"); | 
 | 	return error; | 
 | } | 
 |  | 
 | static void thaw_tasks(bool nosig_only) | 
 | { | 
 | 	struct task_struct *g, *p; | 
 |  | 
 | 	read_lock(&tasklist_lock); | 
 | 	do_each_thread(g, p) { | 
 | 		if (!freezeable(p)) | 
 | 			continue; | 
 |  | 
 | 		if (nosig_only && should_send_signal(p)) | 
 | 			continue; | 
 |  | 
 | 		thaw_process(p); | 
 | 	} while_each_thread(g, p); | 
 | 	read_unlock(&tasklist_lock); | 
 | } | 
 |  | 
 | void thaw_processes(void) | 
 | { | 
 | 	printk("Restarting tasks ... "); | 
 | 	thaw_tasks(true); | 
 | 	thaw_tasks(false); | 
 | 	schedule(); | 
 | 	printk("done.\n"); | 
 | } | 
 |  | 
 | EXPORT_SYMBOL(refrigerator); |