diff options
Diffstat (limited to 'include/linux/freezer.h')
| -rw-r--r-- | include/linux/freezer.h | 159 | 
1 files changed, 76 insertions, 83 deletions
diff --git a/include/linux/freezer.h b/include/linux/freezer.h index a5386e3ee75..0ab54e16a91 100644 --- a/include/linux/freezer.h +++ b/include/linux/freezer.h @@ -5,71 +5,58 @@  #include <linux/sched.h>  #include <linux/wait.h> +#include <linux/atomic.h>  #ifdef CONFIG_FREEZER +extern atomic_t system_freezing_cnt;	/* nr of freezing conds in effect */ +extern bool pm_freezing;		/* PM freezing in effect */ +extern bool pm_nosig_freezing;		/* PM nosig freezing in effect */ +  /*   * Check if a process has been frozen   */ -static inline int frozen(struct task_struct *p) +static inline bool frozen(struct task_struct *p)  {  	return p->flags & PF_FROZEN;  } -/* - * Check if there is a request to freeze a process - */ -static inline int freezing(struct task_struct *p) -{ -	return test_tsk_thread_flag(p, TIF_FREEZE); -} - -/* - * Request that a process be frozen - */ -static inline void set_freeze_flag(struct task_struct *p) -{ -	set_tsk_thread_flag(p, TIF_FREEZE); -} +extern bool freezing_slow_path(struct task_struct *p);  /* - * Sometimes we may need to cancel the previous 'freeze' request + * Check if there is a request to freeze a process   */ -static inline void clear_freeze_flag(struct task_struct *p) -{ -	clear_tsk_thread_flag(p, TIF_FREEZE); -} - -static inline bool should_send_signal(struct task_struct *p) +static inline bool freezing(struct task_struct *p)  { -	return !(p->flags & PF_FREEZER_NOSIG); +	if (likely(!atomic_read(&system_freezing_cnt))) +		return false; +	return freezing_slow_path(p);  }  /* Takes and releases task alloc lock using task_lock() */ -extern int thaw_process(struct task_struct *p); +extern void __thaw_task(struct task_struct *t); -extern void refrigerator(void); +extern bool __refrigerator(bool check_kthr_stop);  extern int freeze_processes(void);  extern int freeze_kernel_threads(void);  extern void thaw_processes(void); -static inline int try_to_freeze(void) +static inline bool try_to_freeze(void)  { -	if (freezing(current)) { -		refrigerator(); -		return 1; -	} else -		return 0; +	might_sleep(); +	if (likely(!freezing(current))) +		return false; +	return __refrigerator(false);  } -extern bool freeze_task(struct task_struct *p, bool sig_only); -extern void cancel_freezing(struct task_struct *p); +extern bool freeze_task(struct task_struct *p); +extern bool set_freezable(void);  #ifdef CONFIG_CGROUP_FREEZER -extern int cgroup_freezing_or_frozen(struct task_struct *task); +extern bool cgroup_freezing(struct task_struct *task);  #else /* !CONFIG_CGROUP_FREEZER */ -static inline int cgroup_freezing_or_frozen(struct task_struct *task) +static inline bool cgroup_freezing(struct task_struct *task)  { -	return 0; +	return false;  }  #endif /* !CONFIG_CGROUP_FREEZER */ @@ -80,33 +67,27 @@ static inline int cgroup_freezing_or_frozen(struct task_struct *task)   * appropriately in case the child has exited before the freezing of tasks is   * complete.  However, we don't want kernel threads to be frozen in unexpected   * places, so we allow them to block freeze_processes() instead or to set - * PF_NOFREEZE if needed and PF_FREEZER_SKIP is only set for userland vfork - * parents.  Fortunately, in the ____call_usermodehelper() case the parent won't - * really block freeze_processes(), since ____call_usermodehelper() (the child) - * does a little before exec/exit and it can't be frozen before waking up the - * parent. + * PF_NOFREEZE if needed. Fortunately, in the ____call_usermodehelper() case the + * parent won't really block freeze_processes(), since ____call_usermodehelper() + * (the child) does a little before exec/exit and it can't be frozen before + * waking up the parent.   */ -/* - * If the current task is a user space one, tell the freezer not to count it as - * freezable. - */ + +/* Tell the freezer not to count the current task as freezable. */  static inline void freezer_do_not_count(void)  { -	if (current->mm) -		current->flags |= PF_FREEZER_SKIP; +	current->flags |= PF_FREEZER_SKIP;  }  /* - * If the current task is a user space one, tell the freezer to count it as - * freezable again and try to freeze it. + * Tell the freezer to count the current task as freezable again and try to + * freeze it.   */  static inline void freezer_count(void)  { -	if (current->mm) { -		current->flags &= ~PF_FREEZER_SKIP; -		try_to_freeze(); -	} +	current->flags &= ~PF_FREEZER_SKIP; +	try_to_freeze();  }  /* @@ -118,21 +99,29 @@ static inline int freezer_should_skip(struct task_struct *p)  }  /* - * Tell the freezer that the current task should be frozen by it + * These macros are intended to be used whenever you want allow a task that's + * sleeping in TASK_UNINTERRUPTIBLE or TASK_KILLABLE state to be frozen. Note + * that neither return any clear indication of whether a freeze event happened + * while in this function.   */ -static inline void set_freezable(void) -{ -	current->flags &= ~PF_NOFREEZE; -} -/* - * Tell the freezer that the current task should be frozen by it and that it - * should send a fake signal to the task to freeze it. - */ -static inline void set_freezable_with_signal(void) -{ -	current->flags &= ~(PF_NOFREEZE | PF_FREEZER_NOSIG); -} +/* Like schedule(), but should not block the freezer. */ +#define freezable_schedule()						\ +({									\ +	freezer_do_not_count();						\ +	schedule();							\ +	freezer_count();						\ +}) + +/* Like schedule_timeout_killable(), but should not block the freezer. */ +#define freezable_schedule_timeout_killable(timeout)			\ +({									\ +	long __retval;							\ +	freezer_do_not_count();						\ +	__retval = schedule_timeout_killable(timeout);			\ +	freezer_count();						\ +	__retval;							\ +})  /*   * Freezer-friendly wrappers around wait_event_interruptible(), @@ -152,47 +141,51 @@ static inline void set_freezable_with_signal(void)  #define wait_event_freezable(wq, condition)				\  ({									\  	int __retval;							\ -	do {								\ +	for (;;) {							\  		__retval = wait_event_interruptible(wq, 		\  				(condition) || freezing(current));	\ -		if (__retval && !freezing(current))			\ +		if (__retval || (condition))				\  			break;						\ -		else if (!(condition))					\ -			__retval = -ERESTARTSYS;			\ -	} while (try_to_freeze());					\ +		try_to_freeze();					\ +	}								\  	__retval;							\  }) -  #define wait_event_freezable_timeout(wq, condition, timeout)		\  ({									\  	long __retval = timeout;					\ -	do {								\ +	for (;;) {							\  		__retval = wait_event_interruptible_timeout(wq,		\  				(condition) || freezing(current),	\  				__retval); 				\ -	} while (try_to_freeze());					\ +		if (__retval <= 0 || (condition))			\ +			break;						\ +		try_to_freeze();					\ +	}								\  	__retval;							\  }) +  #else /* !CONFIG_FREEZER */ -static inline int frozen(struct task_struct *p) { return 0; } -static inline int freezing(struct task_struct *p) { return 0; } -static inline void set_freeze_flag(struct task_struct *p) {} -static inline void clear_freeze_flag(struct task_struct *p) {} -static inline int thaw_process(struct task_struct *p) { return 1; } +static inline bool frozen(struct task_struct *p) { return false; } +static inline bool freezing(struct task_struct *p) { return false; } +static inline void __thaw_task(struct task_struct *t) {} -static inline void refrigerator(void) {} +static inline bool __refrigerator(bool check_kthr_stop) { return false; }  static inline int freeze_processes(void) { return -ENOSYS; }  static inline int freeze_kernel_threads(void) { return -ENOSYS; }  static inline void thaw_processes(void) {} -static inline int try_to_freeze(void) { return 0; } +static inline bool try_to_freeze(void) { return false; }  static inline void freezer_do_not_count(void) {}  static inline void freezer_count(void) {}  static inline int freezer_should_skip(struct task_struct *p) { return 0; }  static inline void set_freezable(void) {} -static inline void set_freezable_with_signal(void) {} + +#define freezable_schedule()  schedule() + +#define freezable_schedule_timeout_killable(timeout)			\ +	schedule_timeout_killable(timeout)  #define wait_event_freezable(wq, condition)				\  		wait_event_interruptible(wq, condition)  |