diff --git a/include/linux/sched.h b/include/linux/sched.h index b61d039b665f..59eb23e73fa0 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2596,6 +2596,7 @@ extern void xtime_update(unsigned long ticks); extern int wake_up_state(struct task_struct *tsk, unsigned int state); extern int wake_up_process(struct task_struct *tsk); +extern int wake_up_process_no_notif(struct task_struct *tsk); extern void wake_up_new_task(struct task_struct *tsk); #ifdef CONFIG_SMP extern void kick_process(struct task_struct *tsk); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 76e265ad1abf..01837c230d4d 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -4360,6 +4360,9 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) u64 wallclock; struct related_thread_group *grp = NULL; #endif + bool freq_notif_allowed = !(wake_flags & WF_NO_NOTIFIER); + + wake_flags &= ~WF_NO_NOTIFIER; /* * If we are going to wake up a thread waiting for CONDITION we @@ -4477,11 +4480,14 @@ out: atomic_notifier_call_chain(&migration_notifier_head, 0, (void *)&mnd); - if (!same_freq_domain(src_cpu, cpu)) { - check_for_freq_change(cpu_rq(cpu)); - check_for_freq_change(cpu_rq(src_cpu)); - } else if (heavy_task) - check_for_freq_change(cpu_rq(cpu)); + if (freq_notif_allowed) { + if (!same_freq_domain(src_cpu, cpu)) { + check_for_freq_change(cpu_rq(cpu)); + check_for_freq_change(cpu_rq(src_cpu)); + } else if (heavy_task) { + check_for_freq_change(cpu_rq(cpu)); + } + } return success; } @@ -4561,6 +4567,26 @@ int wake_up_process(struct task_struct *p) } EXPORT_SYMBOL(wake_up_process); +/** + * wake_up_process_no_notif - Wake up a specific process without notifying + * governor + * @p: The process to be woken up. + * + * Attempt to wake up the nominated process and move it to the set of runnable + * processes. + * + * Return: 1 if the process was woken up, 0 if it was already running. + * + * It may be assumed that this function implies a write memory barrier before + * changing the task state if and only if any tasks are woken up. + */ +int wake_up_process_no_notif(struct task_struct *p) +{ + WARN_ON(task_is_stopped_or_traced(p)); + return try_to_wake_up(p, TASK_NORMAL, WF_NO_NOTIFIER); +} +EXPORT_SYMBOL(wake_up_process_no_notif); + int wake_up_state(struct task_struct *p, unsigned int state) { return try_to_wake_up(p, state, 0); diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index c30c12097d02..0e55971e3e96 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1596,6 +1596,7 @@ static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev) #define WF_SYNC 0x01 /* waker goes to sleep after wakeup */ #define WF_FORK 0x02 /* child wakeup after fork */ #define WF_MIGRATED 0x4 /* internal use, task got migrated */ +#define WF_NO_NOTIFIER 0x08 /* do not notify governor */ /* * To aid in avoiding the subversion of "niceness" due to uneven distribution